
Vue mixins são a maneira recomendada de compartilhar funcionalidades comuns entre componentes. Eles estão perfeitamente bem até você usar mais de um para eles. Isso ocorre porque eles estão implícitos no design e poluem o contexto do seu componente. Vamos tentar consertar isso, dando a eles o máximo de explicações possível.
Objetivo
Gostaríamos de ter um mixin global que dê a qualquer componente um suporte chamado types
e produz uma matriz de classes CSS chamadas mods
derivadas de baseClass
.
Dada esta marcação:
<SampleComponent :types="['active', 'block']"></SampleComponent>
Esperamos ter isso (assumindo que nossa baseClass
seja sample-component
):
<div class="sample-component sample-component--active sample-component--block"></div>
Abordagem ingênua
Ao ler apenas a documentação do Vue, seu primeiro pensamento pode ser usar apenas a mesclagem de propriedades incorporada e fornecer mods
como uma propriedade computada em um componente desejado.
// SampleComponent.vue <template> <div class="sample-component" :class="mods"><slot /></div> </template>
import bemMods from 'bemMods.js'; export default { name: 'SampleComponent', mixins: [ bemMods('sample-component') ] }
Essa abordagem sofre de muitos problemas:
- Código padrão em todos os componentes. (pelo menos em uma abordagem Vue)
- Dependência de um argumento
baseClass
. - Nenhuma indicação clara de onde a propriedade
mods
veio. - Conflitos de nomes são facilmente possíveis.
Vamos tentar corrigir todos esses problemas na próxima etapa.
Mixin com uma exportação explícita
O Vue possui um mecanismo de injeção de dependência, chamado Inject \ Provide . Pode potencialmente resolver nosso problema com o contexto poluidor.
Inicialmente, vamos mudar de um mixin simples para um plug-in, que aceita opções, que usaremos posteriormente para evitar conflitos de nome.
Em segundo lugar, também podemos reutilizar o nome de nosso componente como uma baseClass
e não incluir isso como uma opção personalizada em cada componente.
E, por último, deixaremos uma opção para passar baseClass
como argumento de função, caso a baseClass
do nosso componente não corresponda ao seu nome.
Agora estamos prontos para registrar nosso plugin globalmente.
import Vue from 'vue'; import bemMods from 'bemMods.js'; Vue.use(bemMods);
Também podemos personalizar como nossos objetos são chamados, fornecendo um objeto de opções.
import Vue from 'vue'; import bemMods from 'bemMods.js'; Vue.use(bemMods, { propName: 'modifiers', modsName: 'classes' });
E aqui está como nosso componente se parece após a refatoração da mixagem:
<template> <div class="sample-component" :class="mods"><slot /></div> </template>
export default { name: 'SampleComponent',
Vamos imaginar que nosso componente não tem name
ou tem uma baseClass
diferente do nome:
<template> <div class="special-component" :class="mods('snowflake')"><slot /></div> </template>
export default { name: 'SpecialComponent', inject: ['mods'] }
Ou se queremos estar prontos para uma refatoração ou remoção de plug-in:
export default { name: 'SomeComponent', inject: {
Você também pode usar o Symbol
como um nome de mods para eliminar completamente os conflitos de nomes, mas isso exigiria a inclusão desse símbolo em todos os componentes em que você gostaria de usar o bemMods
.
Não especificamos implicitamente nosso nome de prop, mas essa é uma limitação principal do mixin, que tentamos superar com um nome de prop customizado em uma configuração de plug-in.
Espero que isso tenha sido útil para você e você encontrou uma maneira melhor de escrever mixins para o Vue.