
Los mixins de Vue son la forma recomendada de compartir funcionalidades comunes entre componentes. Están perfectamente bien hasta que use más de uno para ellos. Esto se debe a que están implícitos por diseño y contaminan el contexto de su componente. Tratemos de arreglar esto dándoles tanta explicitación como podamos.
Gol
Nos gustaría tener un mixin global que proporcione a cualquier componente un accesorio llamado types
y genere una matriz de clases CSS llamadas mods
que se derivan de baseClass
.
Dado este marcado:
<SampleComponent :types="['active', 'block']"></SampleComponent>
Esperaríamos tener esto (suponiendo que nuestra baseClass
sea sample-component
):
<div class="sample-component sample-component--active sample-component--block"></div>
Enfoque ingenuo
Al leer solo la documentación de Vue, su primer pensamiento podría ser simplemente usar la combinación de propiedades incorporada y proporcionar mods
como una propiedad calculada en un componente deseado.
// 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') ] }
Este enfoque tiene muchos problemas:
- Código repetitivo en cada componente. (al menos en un enfoque Vue)
- Dependencia de un argumento
baseClass
. - No hay una indicación clara de dónde proviene la propiedad
mods
. - Los conflictos de nombres son fácilmente posibles.
Intentaremos solucionar todos estos problemas en el siguiente paso.
Mixin con una exportación explícita
Vue tiene un mecanismo de inyección de dependencia, llamado Inject \ Provide . Potencialmente puede resolver nuestro problema con el contexto contaminante.
Al principio, cambiemos de un simple mixin a un complemento, que acepta opciones, que usaremos más adelante para evitar conflictos de nombres.
En segundo lugar, también podemos reutilizar el nombre de nuestro componente como baseClass
y no incluirlo como una opción personalizada en cada componente.
Y, por último, dejaremos una opción para pasar baseClass
como argumento de función en caso de que baseClass
nuestro componente no coincida con su nombre.
Ahora estamos listos para registrar nuestro complemento a nivel mundial.
import Vue from 'vue'; import bemMods from 'bemMods.js'; Vue.use(bemMods);
También podemos personalizar cómo se llaman nuestros accesorios, proporcionando un objeto de opciones.
import Vue from 'vue'; import bemMods from 'bemMods.js'; Vue.use(bemMods, { propName: 'modifiers', modsName: 'classes' });
Y así es como se ve nuestro componente después de la refactorización mixin:
<template> <div class="sample-component" :class="mods"><slot /></div> </template>
export default { name: 'SampleComponent',
Imaginemos que nuestro componente no tiene name
o tiene una baseClass
diferente de su nombre:
<template> <div class="special-component" :class="mods('snowflake')"><slot /></div> </template>
export default { name: 'SpecialComponent', inject: ['mods'] }
O si queremos estar listos para una refactorización o eliminación de complementos:
export default { name: 'SomeComponent', inject: {
También puede usar Symbol
como un nombre de mods para eliminar completamente los conflictos de nombres, pero eso requeriría que incluya ese símbolo en cada uno de los componentes donde le gustaría usar bemMods
.
No especificamos implícitamente nuestro nombre de utilería, pero esa es una limitación de mezcla principal, que intentamos superar con un nombre de utilería personalizado en una configuración de complemento.
Espero que esto te haya sido útil y hayas encontrado una mejor manera de escribir mixins para Vue.