Vue Features zum Erinnern

Wir vom Ptah- Team haben uns entschlossen, etwas weiter als das übliche SPA zu gehen, und versucht, Vue als Zielseiten-Designer zu verwenden. Und jetzt möchten wir einen Teil unserer Erfahrungen teilen.

Dieser Artikel richtet sich in erster Linie an diejenigen, die gerade mit Vue begonnen haben und dessen Funktionen und Fähigkeiten besser kennenlernen möchten. Hier möchte ich über einige der Funktionen des Frameworks sprechen, die von unerfahrenen Entwicklern oft unverdient vergessen werden.

Renderfunktionen


Komponentenvorlagen sind eines der Dinge, für die Entwickler Vue lieben. Sie sind einfach und logisch, dank ihnen hat das Framework eine niedrige Eintrittsschwelle. Die Vorlagensyntax reicht in 90% der Fälle aus, um logischen und schönen Code zu schreiben. Aber was tun, wenn Sie in den verbleibenden 10% sind und keine kompakte Komponente schreiben können? Die Renderfunktion hilft Ihnen dabei.

Lassen Sie uns anhand des Beispiels aus der Dokumentation sehen, was es ist:

Vue.component('anchored-heading', {
 render: function (createElement) {
   return createElement(
     'h' + this.level,   //  
     this.$slots.default //   
   )
 },
 props: {
   level: {
     type: Number,
     required: true
   }
 }
})

Die Komponente mit verankerten Überschriften akzeptiert die Ebene- Eigenschaft und zeichnet das Titel-Tag. Also Aufnahme

<anchored-heading :level="1">, !</anchored-heading>

Wird konvertiert zu

<h1>, !</h1>

Wenn diese Komponente unter Verwendung einer Standardvorlage beschrieben würde, würde sie bis zu 6 v-if- Bedingungen enthalten , die verschiedene Ebenen von Headern beschreiben:

<h1 v-if="level === 1">
 <slot></slot>
</h1>
<h2 v-if="level === 2">
 <slot></slot>
</h2>
<h3 v-if="level === 3">
 <slot></slot>
</h3>
<h4 v-if="level === 4">
 <slot></slot>
</h4>
<h5 v-if="level === 5">
 <slot></slot>
</h5>
<h6 v-if="level === 6">
 <slot></slot>
</h6>

Wie es funktioniert?


Die Rendermethode verwendet zwei Argumente. Das erste Argument für createElement ist eine Funktion, die beschreibt, welches Vue-Element erstellt werden soll. In der Community ist es üblich, createElement auf einen Buchstaben abzukürzen - h . Das zweite Argument ist Kontext , um auf Kontextdaten zuzugreifen.

createElement akzeptiert drei Argumente:

  1. Das zu erstellende Element. Dies kann nicht nur ein HTML-Tag sein, sondern auch ein Komponentenname. Dieses Argument ist erforderlich;
  2. Ein Objekt mit Daten. Es kann eine Liste von Klassen, Stilen, Eingabeparametern für die Komponente, Methoden zur Behandlung von Ereignissen usw. enthalten. Weitere Einzelheiten finden Sie in der Dokumentation. Optionales Argument;
  3. Untergeordnete virtuelle Knoten. Es kann entweder eine Zeichenfolge oder ein Array sein. Im obigen Beispiel ist dies. $ Slots.default .

Renderfunktionen können in den unerwartetsten Situationen hilfreich sein. In Ptah müssen wir beispielsweise häufig das Style- Tag auf der Seite verwenden, damit einige Designerelemente ordnungsgemäß funktionieren. Vue verbietet jedoch die Verwendung dieses Tags innerhalb der Vorlagenkomponente . Diese Einschränkung kann dank eines kleinen Wrappers leicht umgangen werden:

Vue.component('v-style', {
 render: function (h) {
   return h('style', this.$slots.default)
 }
})

Jetzt in den Vorlagen, anstelle des Stil - Tag, können Sie mit v-Stil .

Sobald Ihnen der Eindruck entsteht, dass die Standardfunktionen von Vue-Vorlagen nicht ausreichen, denken Sie an die Renderfunktionen. Sie sehen nur auf den ersten Blick kompliziert aus, aber Sie können alle Funktionen nutzen, die JS in ihnen bietet.

Mixins


Haben Sie mehrere ähnliche Komponenten mit doppeltem Code? Mixins oder Verunreinigungen tragen zur Einhaltung des DRY-Prinzips bei - die Funktionalität von Mixins kann in mehreren Komponenten gleichzeitig verwendet werden.

Nehmen wir ein Beispiel. Angenommen, wir haben zwei Komponenten mit ähnlicher Logik:

export default  {
  name: 'TextElement',

  data () {
    return {
      elementName: 'Text',
      showEditor: false,
      editor: null
    }
  },
  
  methods: {
    initEditor () {
      this.showEditor = true
      this.editor = new Editor(this.elementName)
    }
  }
}

export default  {
  name: 'ButtonElement',

  data () {
    return {
      elementName: 'Button',
      showEditor: false,
      editor: null
    }
  },
  
  methods: {
    initEditor () {
      this.showEditor = true
      this.editor = new Editor(this.elementName)
    }
  }
}

Die Komponenten sind unterschiedlich, haben aber die gleiche Logik. Um es zu machen, müssen Sie eine reguläre js-Datei erstellen. Es wäre logisch, es im Mixins- Verzeichnis neben den Komponenten abzulegen .

// mixin.js
export default  {
  data () {
    return {
      showEditor: false,
      editor: null
    }
  },
  
  methods: {
    initEditor () {
      this.showEditor = true
      this.editor = new Editor(this.elementName)
    }
  }
}

// TextElement.vue
import mixin from './mixins/mixin'

export default  {
  name: 'TextElement',

  mixins: [mixin]  //  

  data () {
    return {
      elementName: 'Text',
    }
  },
}

// ButtonElement.vue
import mixin from './mixins/mixin'

export default  {
  name: 'ButtonElement',

  mixins: [mixin]

  data () {
    return {
      elementName: 'Button'
    }
  }
}

Wie Sie dem Beispiel entnehmen können, wurde fast die gesamte Logik auf das Mixin migriert. Bei Verwendung von Verunreinigungen in den Komponenten verschmelzen alle Optionen. In der Komponente können Sie die Methode initEditor () frei aufrufen , und umgekehrt wird der Elementname der Komponente in der Verunreinigung verwendet . In diesem Fall werden die Datenobjekte rekursiv zusammengeführt, und die Eigenschaften der Komponente haben Vorrang.

Die Vorteile von Verunreinigungen liegen auf der Hand - dies ist die Wiederverwendung von Code. Aber es gibt ein Minus. Dieses Beispiel ist synthetisch, nur ein paar Zeilen. Reale Komponenten, wie sie in Ptah verwendet werden, können in ein paar hundert Codezeilen geschrieben werden. Einer Person, die diesen Code nicht geschrieben hat, wird nicht immer klar sein, wie er funktioniert, insbesondere wenn sie das Hinzufügen von Mixins zur Komponente übersieht. Leider funktioniert es nicht, dieses Minus loszuwerden. Ich kann zwei Dinge empfehlen: Beschreiben Sie die Funktionsweise der Komponente in JSDoc und verwenden Sie spezielle Namen für Eigenschaften aus der Verunreinigung (Sie können beispielsweise ein Präfix hinzufügen, das Sie im Voraus mit dem Team vereinbaren).

Bereitstellen / Injizieren


Dieses Optionspaar wird immer zusammen verwendet und ermöglicht es Ihnen, Daten von der übergeordneten Komponente in die gesamte Hierarchie ihrer Nachkommen zu übertragen. Diese Optionen werden hauptsächlich zum Schreiben von Plugins verwendet. In der offiziellen Dokumentation wird die Verwendung in Plugins nicht empfohlen. In Anwendungen baut die Kommunikation zwischen Komponenten sehr gut auf Vuex auf. Diese Funktionalität verdient jedoch noch Aufmerksamkeit.

Wie es funktioniert?


Zuerst müssen wir die Daten in der übergeordneten Komponente definieren, die wir an ihre Nachkommen weitergeben.

// Parent.vue        
export default {
  provide: {
   device: 'is-desktop'
  }
}

Jetzt müssen die übertragenen Daten in die untergeordnete Komponente eingebettet werden.

// Child.vue    
export default {
  inject: ['device'],

  created () {
   console.log(this.device) // => "is-desktop"
  }
}

Wie Sie dem Beispiel entnehmen können, ist alles recht einfach. Es ist jedoch ein signifikantes Minus zu beachten: Die Daten aus dem Bereitstellungs- / Injektionspaket sind standardmäßig nicht reaktiv! Dieser Nachteil kann jedoch mit Object.defineProperty leicht umgangen werden :

provide () {
 let device = {}
 Object.defineProperty(device, 'type', { enumerable: true, get: () => this.device })
 return { device }
},

data () {
 return {
   device: 'is-desktop'
 }
}

Wenn Sie nun this.device im übergeordneten Gerät ändern, wird es in den Nachkommen geändert.

Komponenten-Meta


Es gibt Situationen, in denen nicht im Voraus bekannt ist, welche Komponente im Code verwendet wird. Betrachten Sie ein Beispiel aus unserem Editor. Die Aufgabe lautet wie folgt: Zeigen Sie im bedingten Bereich von FirstScreen die Elemente Text, Logo und Schaltfläche an und fügen Sie diesen Elementen SocialIcons hinzu .

Es ist also offensichtlich, dass wir eine Abschnittskomponente haben werden, die als Container für die Elemente und 4 Komponenten für die Elemente selbst dient. Die Struktur wird ungefähr wie folgt sein:

/ sections
 -- FirstScreen.vue
/ elements
 -- Text.vue
 -- Logo.vue
 -- Button.vue
 -- SocialIcons.vue

Es wäre eine äußerst unkluge Entscheidung , alle Komponenten von Elementen gleichzeitig zur FirstScreen- Vorlage hinzuzufügen und sie dann unter Bedingungen zu wechseln. Für solche Aufgaben gibt es ein einfaches und wunderbares Werkzeug:

<component :is="%componentName%"/>

Das Komponentenelement mit dem Attribut : is schreibt einfach den Namen der Komponente. Und dank ihm ist unsere Aufgabe einfach gelöst:

<script>
export default  {
  name: 'FirstScreen',

  data () {
    return {
      elements: [
        'Text',
        'Logo',
        'Button',
      ],
    }
  }
}
</script>

<template>
  <div class="first-screen">
    <component v-for="element in elements" :is="element"/>
  </div>
</template>

Im Elements- Array haben wir die Namen der Komponenten geschrieben und diese Komponenten dann einfach in einer Schleife innerhalb der FirstScreen- Vorlage ausgegeben . Um unserem Abschnitt ein Element mit den Symbolen sozialer Netzwerke hinzuzufügen, müssen wir nur this.elements.push ('SocialIcons') ausführen .

All Articles