Dieser Artikel setzt ein grundlegendes Verständnis des Vue.js-Frameworks und der Erstellung von Komponenten darin voraus. Wenn Sie neu bei Vue sind, dann ist diese CSS-Tricks-Reihe ein guter Ausgangspunkt.
Ich war an einem Vue.js-Projekt beteiligt, das die Fähigkeit erforderte, Komponenten programmatisch zu erstellen. Mit programmatisch meine ich, dass Sie die Komponenten vollständig aus JavaScript erstellen und einfügen, ohne etwas in der Vorlage zu schreiben. Dieser Artikel zielt darauf ab zu veranschaulichen, wie sich verschiedene Aspekte der Verwendung von Komponenten in einer Vorlage, wie z. B. Instanziierung, Props-Übergabe, Slots, Mounten, in JavaScript-Code übersetzen.
Normalerweise, wenn Sie mit dem empfohlenen Stil der **Single File Component** arbeiten, hätten Sie eine Komponente namens Button wie folgt:
<template>
<button :class="type"><slot /></button>
</template>
<script>
export default {
name: 'Button',
props: [ 'type' ],
}
</script>
Um sie in einer anderen Komponente zu verwenden, müssen Sie lediglich die Button-Komponente importieren und ihr Tag in der Vorlage einfügen.
<template>
<Button type="primary">Click me!</Button>
</template>
<script>
import Button from 'Button.vue'
export default {
name: 'App',
components: { Button }
}
</script>
In meinem Fall weiß ich nicht, welche Komponente in der Vorlage eingefügt werden soll und wo sie eingefügt werden soll. Diese Information ist erst zur Laufzeit verfügbar. Also brauchte ich eine Möglichkeit, eine dynamische Komponenteninstanz für jede übergebene Komponente zu erstellen und sie zur Laufzeit in das DOM einzufügen.
Instanz erstellen
Der allererste Gedanke, den ich hatte, um eine dynamische Instanz einer gegebenen Komponente zu erstellen, war, sie an new zu übergeben, und es würde mir die tatsächliche Instanz geben. Aber wenn Sie genau hinsehen, sind die script-Blöcke in jedem der obigen Komponentencodes allesamt ein einfaches Objekt und keine Klasse (Konstruktorfunktion). Wenn ich das mache
import Button from 'Button.vue'
var instance = new Button()
... schlägt es fehl. Wir brauchen eine Klasse. Oder, einfach ausgedrückt, eine Konstruktorfunktion. Der Weg dorthin besteht darin, das Komponentenobjekt an Vue.extend zu übergeben, um eine Unterklasse des Vue-Konstruktors zu erstellen. Jetzt können wir daraus mit dem new-Schlüsselwort eine Instanz erstellen.
import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass()
Hurra! Schritt 1 erledigt! Jetzt müssen wir es in das DOM einfügen.
In das DOM einfügen
Jede Vue-Instanz hat eine Methode namens $mount, die die Komponenteninstanz auf dem Element montiert, das Sie ihr übergeben (d. h. sie ersetzt das übergebene Element durch die Komponenteninstanz). Das war kein gewünschtes Verhalten. Ich wollte meine Komponenteninstanzen in ein DOM-Element einfügen. Dafür gibt es auch einen Weg. Aus der offiziellen Dokumentation:
Wenn das Argument
elementOrSelectornicht angegeben wird, wird die Vorlage als Element außerhalb des Dokuments gerendert, und Sie müssen die native DOM-API verwenden, um sie selbst in das Dokument einzufügen.
Das habe ich getan.
import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass()
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
Im obigen Code gibt es ein paar Dinge zu beachten.
Erstens ist $refs die empfohlene Methode, um eine Referenz auf ein DOM-Element in Vue.js zu erhalten. Sie geben ein Attribut für das DOM-Element an, auf das Sie verweisen möchten (in diesem Fall <div ref="container"></div>), und dieses Element ist dann über den angegebenen Schlüssel auf der $refs-Eigenschaft der Komponente verfügbar.
Zweitens können Sie die Eigenschaft $el verwenden, um die native DOM-Elementreferenz von einer Vue-Komponenteninstanz zu erhalten.
Props an die Instanz übergeben
Als Nächstes musste ich meiner Button-Instanz einige Props übergeben. Insbesondere den type-Prop. Die Vue-Konstruktorfunktion akzeptiert ein Optionenobjekt, das wir verwenden können, um zugehörige Dinge zu übergeben und zu initialisieren. Für die Übergabe von Props gibt es einen Schlüssel namens propsData, den wir wie folgt verwenden können:
import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass({
propsData: { type: 'primary' }
})
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
Wir sind fast fertig, mit einem letzten verbleibenden Teil. Bei der normalen Vorlagenmethode haben wir den Button wie folgt verwendet: <Button>Klick mich!</Button>;. Wir haben einfach den inneren Text zwischen den Tags geschrieben, und er wurde mithilfe von slot im endgültigen Button-Tag gerendert. Aber wie übergeben wir ihn jetzt?
Slot festlegen
Wenn Sie Slots in Vue.js verwendet haben, wissen Sie vielleicht, dass die Slots auf jeder Instanz über die Eigenschaft $slots zugänglich sind. Und wenn keine benannten Slots verwendet werden, sind die Slots als Array unter $slots.default verfügbar. Das ist genau der Schlüssel, den wir auf der Instanz ändern werden, um den inneren Text unseres Buttons festzulegen. Denken Sie daran, dass dies vor dem Mounten der Instanz geschehen muss. Beachten Sie, dass wir in unserem Fall nur einen einfachen String in den Slot gesetzt haben, weil das alles war, was wir brauchten. Sie können ihm aber auch komplexere DOM-Strukturen in Form von virtuellen Knoten oder VNodes unter Verwendung der Funktion createElement übergeben. Sie können hier über die Erstellung von virtuellen Knoten in der Vue.js-Dokumentation lesen. Dank eines Mitglieds des Vue-Kernteams, Rahul, für die Empfehlung dieser Technik.
import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass({
propsData: { type: 'primary' }
})
instance.$slots.default = [ 'Click me!' ]
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
Finale Demo
Ich hoffe, dieser Artikel hat Ihnen gefallen. Folgen Sie mir auf Twitter, wo ich weitere Artikel und meine Nebenprojekte teile.
Toller Artikel! Aber es gibt noch eine Funktion. Vue ermöglicht es uns, eine Eltern-Kind-Beziehung für manuell erstellte Instanzen herzustellen, indem wir die Option
parentübergeben, was bedeutet, dass wirprovide/injectfür unsere Komponenten verwenden können: Dokumentation hierUnd hier ist der aktualisierte Code aus dem Artikel: https://codesandbox.io/s/045k690vyw?autoresize=1&module=%2FApp.vue&moduleview=1
Dies zeigt, wie
provide/injectverwendet wird, um das Thema für eine manuell erstellte Komponenteninstanz zu ändern.Der richtige Link für die Demo: https://codesandbox.io/s/045k690vyw?autoresize=1&module=%2FApp.vue
großartig
Super gut!
Ich denke, es gibt eine Möglichkeit,
$mountzu verwenden, ohneappendChild()zu benutzen. Der beste Weg ist,$elnicht als Option anzugeben und einfachinstance.$mount(DESTINATION)zu verwenden.Hier ist das aktualisierte Codesandbox: https://codesandbox.io/s/kk4rxzon33?module=%2FApp.vue
Im Artikel erkläre ich, warum dieser empfohlene Weg in meinem Fall nicht in Ordnung war.
Oh, ja, das stimmt, es ersetzt das
DESTINATION-Element. Das habe ich übersehen, entschuldigen Sie.Wenn Sie diesen Artikel lesen, empfehle ich dringend, dies nicht zu tun. Stattdessen können Sie Ihr einfaches Objektkomponente einfach an
<component :is="someObject">übergeben und dann Eigenschaften binden und Kinder wie gewohnt übergeben. Meiner Meinung nach sind Präfix-Attribute und -Methoden ein Zeichen dafür, dass Sie vom Weg abweichen und Ihre Arbeit überprüfen sollten.Es ist ein großartiges Beispiel! Aber wie stelle ich eine zweiseitige Bindung zwischen der Komponenteninstanz und dem Elternteil her?