Vue-Mixins auf explizite Weise (anhand eines Beispiels für ein BEM-Modifikator-Plugin)


Vue-Mixins sind die empfohlene Methode, um gemeinsame Funktionen zwischen Komponenten zu teilen. Sie sind vollkommen in Ordnung, bis Sie mehr als eine für sie verwenden. Dies liegt daran, dass sie vom Design her implizit sind und den Kontext Ihrer Komponente verschmutzen. Versuchen wir, dies zu beheben, indem wir ihnen so viel Aussagekraft wie möglich geben.


Ziel


Wir möchten ein globales Mixin, das jeder Komponente eine Requisite namens types gibt und ein Array von CSS-Klassen namens mods ausgibt, die von baseClass .


Angesichts dieses Aufschlags:


 <SampleComponent :types="['active', 'block']"></SampleComponent> 

Wir würden dies erwarten (vorausgesetzt, unsere baseClass ist eine sample-component ):


 <div class="sample-component sample-component--active sample-component--block"></div> 

Naiver Ansatz


Wenn Sie nur die Vue-Dokumentation lesen, besteht Ihr erster Gedanke möglicherweise darin, nur die integrierte Zusammenführung von Eigenschaften zu verwenden und mods als berechnete Eigenschaft in einer gewünschten Komponente bereitzustellen.


 // bemMods.js export default (baseClass) => ({ props: { types: { type: Array, default: () => [] } }, computed: { mods() { return this.types.map(type => `${baseClass}--${type}`); } } }) 

 // 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') ] } 

Dieser Ansatz weist viele Probleme auf:


  1. Boilerplate-Code in jeder Komponente. (zumindest in einem Vue-Ansatz)
  2. Abhängigkeit von einem baseClass Argument.
  3. Keine eindeutige Angabe, woher die mods Eigenschaft stammt.
  4. Namenskonflikte sind leicht möglich.

Wir werden versuchen, all diese Probleme in einem nächsten Schritt zu beheben.


Mischen Sie mit einem expliziten Export


Vue verfügt über einen Abhängigkeitsinjektionsmechanismus namens Inject \ Provide . Es kann möglicherweise unser Problem mit dem umweltschädlichen Kontext lösen.


Wechseln wir zunächst von einem einfachen Mixin zu einem Plugin, das Optionen akzeptiert, die wir später verwenden, um Namenskonflikte zu vermeiden.


Zweitens können wir den Namen unserer Komponente auch als baseClass und diesen nicht als benutzerdefinierte Option in jede einzelne Komponente aufnehmen.


Und schließlich lassen wir eine Option, um baseClass als Funktionsargument zu übergeben, baseClass die baseClass unserer Komponente nicht mit ihrem Namen übereinstimmt.


 // bemMods.js // Converts ComponentName to component-name const transformName = string => string.replace(/\s+/g, '-').toLowerCase(); const install = (Vue, { propName = 'types', modsName = 'mods' } = {}) => { Vue.mixin({ props: { // Prop name is now dynamic and allows to avoid conflits [propName]: { type: Array, default: () => [], } }, // Dependency injection forces us to explicitly require that function provide: { [modsName](baseClass) { baseClass = baseClass || transformName(this.$options.name); return (this[propName] || []).map(type => `${baseClass}--${type}`); } } }); }; export default { install }; 

Wir sind jetzt bereit, unser Plugin weltweit zu registrieren.


 import Vue from 'vue'; import bemMods from 'bemMods.js'; Vue.use(bemMods); 

Wir können auch anpassen, wie unsere Requisiten aufgerufen werden, indem wir ein Optionsobjekt bereitstellen.


 import Vue from 'vue'; import bemMods from 'bemMods.js'; Vue.use(bemMods, { propName: 'modifiers', modsName: 'classes' }); 

Und so sieht unsere Komponente nach dem Mixin-Refactoring aus:


 <template> <div class="sample-component" :class="mods"><slot /></div> </template> 

 export default { name: 'SampleComponent', // Explicit property inject: ['mods'] } 

Stellen wir uns vor, unsere Komponente hat keinen name oder eine andere baseClass als der Name:


 <template> <div class="special-component" :class="mods('snowflake')"><slot /></div> </template> 

 export default { name: 'SpecialComponent', inject: ['mods'] } 

Oder wenn wir für ein Refactoring oder das Entfernen von Plugins bereit sein möchten:


 export default { name: 'SomeComponent', inject: { // If mixin export property changes name it's now possible to replace it in every single component instance withouth any additional rework 'mods': { // In this case 'mods' becomes 'classes' from: 'classes', } } } 

Sie können Symbol als Mods-Namen verwenden, um Namenskonflikte vollständig zu beseitigen. bemMods müssten Sie dieses Symbol jedoch in jede einzelne Komponente aufnehmen, in der Sie bemMods verwenden bemMods .


Wir haben unseren Requisitennamen nicht implizit angegeben, aber dies ist eine zentrale Mixin-Einschränkung, die wir mit einem benutzerdefinierten Requisitennamen in einer Plugin-Konfiguration zu überwinden versucht haben.


Ich hoffe, das war hilfreich für Sie und Sie haben eine bessere Möglichkeit gefunden, Mixins für Vue zu schreiben.

Source: https://habr.com/ru/post/de441540/


All Articles