Erstellen unseres ersten Vue-Komponenten
Jetzt ist es an der Zeit, tiefer in Vue einzutauchen und unsere eigene benutzerdefinierte Komponente zu erstellen — wir beginnen mit der Erstellung einer Komponente, um jedes Element in der To-Do-Liste darzustellen. Unterwegs lernen wir einige wichtige Konzepte kennen, wie das Aufrufen von Komponenten innerhalb anderer Komponenten, das Übergeben von Daten an diese über Props und das Speichern von Datenzuständen.
Hinweis: Falls Sie Ihren Code mit unserer Version überprüfen müssen, finden Sie eine fertige Version des Beispiel-Vue-App-Codes in unserem todo-vue Repository. Eine Live-Version finden Sie unter https://mdn.github.io/todo-vue/.
Voraussetzungen: |
Vertrautheit mit den grundlegenden HTML, CSS und JavaScript Sprachen, Kenntnis des Terminals/Kommandozeile. Vue-Komponenten werden als Kombination von JavaScript-Objekten geschrieben, die die Daten der App verwalten, und einer HTML-basierten Vorlagensyntax, die die zugrunde liegende DOM-Struktur abbildet. Für die Installation und die Nutzung einige der fortgeschritteneren Funktionen von Vue (wie Single File Components oder Render-Funktionen), brauchen Sie ein Terminal mit Node und npm installiert. |
---|---|
Zielsetzung: | Lernen, wie man eine Vue-Komponente erstellt, sie innerhalb einer anderen Komponente rendert, Daten mit Props an sie übergibt und ihren Zustand speichert. |
Erstellen einer ToDoItem-Komponente
Lassen Sie uns unsere erste Komponente erstellen, die ein einzelnes To-Do-Element anzeigen wird. Wir werden dies nutzen, um unsere Liste von To-Dos aufzubauen.
- Erstellen Sie in Ihrem
moz-todo-vue/src/components
Verzeichnis eine neue Datei mit dem NamenToDoItem.vue
. Öffnen Sie die Datei in Ihrem Code-Editor. - Erstellen Sie den Template-Abschnitt der Komponente, indem Sie
<template></template>
an den Anfang der Datei hinzufügen. - Erstellen Sie einen
<script></script>
Abschnitt unter Ihrem Template-Abschnitt. Fügen Sie innerhalb der<script>
Tags ein standardmäßig exportiertes Objektexport default {}
hinzu, welches Ihr Komponentenobjekt ist.
Ihre Datei sollte nun so aussehen:
<template></template>
<script>
export default {};
</script>
Wir können nun beginnen, tatsächlichen Inhalt zu unserem ToDoItem
hinzuzufügen. Vue-Templates dürfen derzeit nur ein einziges Root-Element haben — ein Element muss alles innerhalb des Template-Abschnitts umschließen (dies wird sich mit Vue 3 ändern). Wir werden dazu ein <div>
verwenden.
-
Fügen Sie nun ein leeres
<div>
in Ihr Komponenten-Template ein. -
Fügen Sie innerhalb dieses
<div>
eine Checkbox und ein entsprechendes Label hinzu. Fügen Sie der Checkbox eineid
hinzu und einfor
Attribut, um die Checkbox mit dem Label zu verknüpfen, wie unten gezeigt.vue<template> <div> <input type="checkbox" id="todo-item" /> <label for="todo-item">My Todo Item</label> </div> </template>
Verwendung von TodoItem in unserer App
Das ist alles in Ordnung, aber wir haben die Komponente noch nicht in unsere App eingefügt, so gibt es keine Möglichkeit, sie zu testen und zu sehen, ob alles funktioniert. Lassen Sie uns das jetzt hinzufügen.
-
Öffnen Sie
App.vue
erneut. -
Fügen Sie am Anfang Ihres
<script>
Tags das Folgende hinzu, um IhreToDoItem
Komponente zu importieren:jsimport ToDoItem from "./components/ToDoItem.vue";
-
Fügen Sie innerhalb Ihres Komponentenobjekts die Eigenschaft
components
hinzu, und innerhalb dieser fügen Sie IhreToDoItem
Komponente hinzu, um sie zu registrieren.
Der Inhalt Ihres <script>
Abschnitts sollte nun so aussehen:
import ToDoItem from "./components/ToDoItem.vue";
export default {
name: "app",
components: {
ToDoItem,
},
};
Dies ist dieselbe Methode, wie die HelloWorld
Komponente zuvor durch die Vue-CLI registriert wurde.
Um die ToDoItem
Komponente tatsächlich in der App zu rendern, müssen Sie in Ihr <template>
Element hinaufgehen und sie als <to-do-item></to-do-item>
Element aufrufen. Beachten Sie, dass der Dateiname der Komponente und seine Repräsentation in JavaScript in PascalCase (z.B. ToDoList
) ist, und das entsprechende benutzerdefinierte Element in kebab-case (z.B. <to-do-list>
) sein muss.
Es ist erforderlich, diesen Stil zu verwenden, wenn Sie Vue-Templates [direkt im DOM] (https://vuejs.org/guide/essentials/component-basics.html#dom-template-parsing-caveats) schreiben.
- Erstellen Sie unterhalb des
<h1>
ein unsortiertes Liste (<ul>
), das einen einzigen Listeneintrag (<li>
) enthält. - Fügen Sie innerhalb des Listeneintrags
<to-do-item></to-do-item>
hinzu.
Der <template>
Abschnitt Ihrer App.vue
Datei sollte nun so aussehen:
<div id="app">
<h1>To-Do List</h1>
<ul>
<li>
<to-do-item></to-do-item>
</li>
</ul>
</div>
Wenn Sie Ihre gerenderte App erneut überprüfen, sollten Sie nun Ihre gerenderte ToDoItem
sehen, bestehend aus einer Checkbox und einem Label.
Komponenten mit Props dynamisch machen
Unsere ToDoItem
Komponente ist noch nicht sehr nützlich, weil wir sie wirklich nur einmal auf einer Seite einfügen können (IDs müssen eindeutig sein), und wir haben keine Möglichkeit, den Text des Labels festzulegen. Nichts davon ist dynamisch.
Was wir brauchen, ist etwas Komponentenstatus. Dies kann erreicht werden, indem wir unserer Komponente Props hinzufügen. Man kann sich Props als ähnlich zu Eingaben in einer Funktion vorstellen. Der Wert eines Props gibt Komponenten einen Anfangszustand, der ihre Anzeige beeinflusst.
Registrieren von Props
In Vue gibt es zwei Möglichkeiten, Props zu registrieren:
- Die erste Methode besteht darin, Props einfach als ein Array von Strings aufzuführen. Jeder Eintrag im Array entspricht dem Namen eines Props.
- Die zweite Methode ist, Props als ein Objekt zu definieren, wobei jeder Schlüssel dem Namen des Props entspricht. Das Auflisten von Props als Objekt erlaubt es Ihnen, Standardwerte anzugeben, Props als erforderlich zu kennzeichnen, grundlegendes Objekt-Typing durchzuführen (insbesondere bei JavaScript-Primitivtypen), und einfache Prop-Validierung durchzuführen.
Hinweis: Prop-Validierung erfolgt nur im Entwicklungsmodus, daher können Sie sich in der Produktion nicht strikt darauf verlassen. Darüber hinaus werden Prop-Validierungsfunktionen aufgerufen, bevor die Komponenteninstanz erstellt wird, so dass sie keinen Zugriff auf den Komponentenstatus (oder andere Props) haben.
Für diese Komponente verwenden wir die Objektregistrierungsmethode.
-
Gehen Sie zurück zu Ihrer
ToDoItem.vue
Datei. -
Fügen Sie eine
props
Eigenschaft innerhalb des Exportdefault {}
Objekts hinzu, das ein leeres Objekt enthält. -
Fügen Sie diesem Objekt zwei Eigenschaften mit den Schlüsseln
label
unddone
hinzu. -
Der
label
Schlüsselwert sollte ein Objekt mit 2 Eigenschaften (oder Props, wie es im Kontext des Zugangs zu den Komponenten genannt wird) sein.- Die erste ist eine
required
(erforderlich) Eigenschaft, die den Werttrue
hat. Dies wird Vue mitteilen, dass wir erwarten, dass jede Instanz dieser Komponente ein Label-Feld hat. Vue warnt uns, wenn eineToDoItem
-Komponente kein Label-Feld hat. - Die zweite Eigenschaft, die wir hinzufügen werden, ist eine
type
(Typ-)Eigenschaft. Setzen Sie den Wert für diese Eigenschaft auf den JavaScriptString
Typ (beachten Sie das große "S"). Dies teilt Vue mit, dass wir erwarten, dass der Wert dieser Eigenschaft ein String ist.
- Die erste ist eine
-
Nun zum
done
Prop.- Fügen Sie zunächst ein
default
Feld hinzu, mit einem Wert vonfalse
. Dies bedeutet, dass wenn keindone
Prop in eineToDoItem
Komponente übergeben wird, dasdone
Prop den Wert false hat (denken Sie daran, dass dies nicht erforderlich ist — wir brauchen nurdefault
bei nicht erforderlichen Props). - Fügen Sie als nächstes ein
type
Feld mit einem Wert vonBoolean
hinzu. Dies teilt Vue mit, dass wir erwarten, dass der Wert dieses Props ein JavaScript-Boolean-Typ ist.
- Fügen Sie zunächst ein
Ihr Komponentenobjekt sollte nun so aussehen:
export default {
props: {
label: { required: true, type: String },
done: { default: false, type: Boolean },
},
};
Verwenden von registrierten Props
Nachdem wir diese Props im Komponentenobjekt definiert haben, können wir diese Variablenwerte in unserem Template verwenden. Beginnen wir damit, das label
Prop zum Komponententemplate hinzuzufügen.
Setzen Sie in Ihrem <template>
den Inhalt des <label>
Elements durch {{label}}
ein.
{{}}
ist eine spezielle Vorlagensyntax in Vue, die es uns ermöglicht, das Ergebnis von JavaScript-Ausdrücken, die in unserer Klasse definiert sind, in unserem Template auszugeben, einschließlich Werten und Methoden. Es ist wichtig zu wissen, dass Inhalte innerhalb von {{}}
als Text und nicht als HTML angezeigt werden. In diesem Fall geben wir den Wert des label
Props aus.
Der Template-Bereich Ihrer Komponente sollte nun wie folgt aussehen:
<template>
<div>
<input type="checkbox" id="todo-item" />
<label for="todo-item">{{ label }}</label>
</div>
</template>
Gehen Sie zurück zu Ihrem Browser und sehen Sie sich das Todo-Element an, das wie zuvor gerendert wird, jedoch ohne Label (oh nein!). Gehen Sie zu den DevTools Ihres Browsers und Sie sehen eine Warnung, die ungefähr so lautet, in der Konsole:
[Vue warn]: Missing required prop: "label" found in ---> <ToDoItem> at src/components/ToDoItem.vue <App> at src/App.vue <Root>
Dies geschieht, weil wir das label
als ein erforderliches Prop markierten, aber wir gaben der Komponente nie dieses Prop — wir haben definiert, wo im Template wir es verwenden wollen, aber wir haben es nicht in die Komponente übergeben, wenn wir sie aufriefen. Lassen Sie uns das beheben.
Fügen Sie in Ihrer App.vue
Datei ein label
Prop zur <to-do-item></to-do-item>
Komponente hinzu, genau wie ein reguläres HTML-Attribut:
<to-do-item label="My ToDo Item"></to-do-item>
Jetzt werden Sie das Label in Ihrer App sehen, und die Warnung wird in der Konsole nicht mehr ausgegeben.
Das war also eine kurze Einführung in Props. Als Nächstes gehen wir darauf ein, wie Vue den Datenstatus beibehält.
Vue's Datenobjekt
Wenn Sie den Wert des label
Props ändern, der in den <to-do-item></to-do-item>
Aufruf Ihrer App
Komponente übergeben wird, sollten Sie sehen, dass er sich aktualisiert. Das ist großartig. Wir haben eine Checkbox mit einem aktualisierbaren Label. Allerdings machen wir derzeit nichts mit dem "done" Prop — wir können die Checkboxes in der Benutzeroberfläche überprüfen, aber nirgendwo in der App wird aufgezeichnet, ob ein To-Do-Element tatsächlich erledigt ist.
Um dies zu erreichen, möchten wir das done
Prop der Komponente an das checked
Attribut auf dem <input>
Element binden, sodass es als Aufzeichnung dienen kann, ob die Checkbox aktiviert ist oder nicht. Es ist jedoch wichtig, dass Props als Einweg-Datenbindung dienen — eine Komponente sollte niemals den Wert ihrer eigenen Props ändern. Dafür gibt es viele Gründe. Einerseits können sich Komponenten, die Props bearbeiten, als Herausforderung beim Debuggen erweisen. Wenn ein Wert an mehrere Kinder übergeben wird, könnte es schwierig sein, nachzuverfolgen, woher die Änderungen dieses Wertes kommen. Außerdem kann das Ändern von Props dazu führen, dass die Komponenten neu gerendert werden. Wenn also eine Komponente ihre Props mutiert, würde dies die Komponente dazu veranlassen, neu zu rendern, was wiederum die Mutation erneut auslösen könnte.
Um dies zu umgehen, können wir den done
Zustand mit der data
Eigenschaft von Vue verwalten. Die data
Eigenschaft ist, wo Sie lokalen Zustand in einer Komponente verwalten können, es lebt innerhalb des Komponentenobjekts neben der props
Eigenschaft und hat die folgende Struktur:
data() {
return {
key: value
}
}
Sie werden feststellen, dass die data
Eigenschaft eine Funktion ist. Dies geschieht, um die Datenwerte für jede Instanz einer Komponente zur Laufzeit eindeutig zu halten — die Funktion wird für jede Komponenteninstanz separat aufgerufen. Wenn Sie Daten einfach als Objekt deklarieren würden, würden alle Instanzen dieser Komponente dieselben Werte teilen. Dies ist ein Nebeneffekt der Art und Weise, wie Vue Komponenten registriert, und etwas, das Sie nicht wollen.
Sie nutzen this
, um auf die Props und andere Eigenschaften einer Komponente von innerhalb des Datenbereichs zuzugreifen, wie Sie vielleicht erwarten würden. Wir werden dies gleich mit einem Beispiel sehen.
Hinweis:
Aufgrund der Art und Weise, wie this
in Pfeilfunktionen (arrow functions) funktioniert (Bindung an den Kontext des Elternteils), könnten Sie nicht auf die notwendigen Attribute von innerhalb der data
zugreifen, wenn Sie eine Pfeilfunktion benutzen. Verwenden Sie also keine Pfeilfunktion für die data
Eigenschaft.
Lassen Sie uns also eine data
Eigenschaft zu unserer ToDoItem
Komponente hinzufügen. Diese wird ein Objekt zurückgeben, das eine einzige Eigenschaft enthält, die wir isDone
nennen, deren Wert this.done
ist.
Aktualisieren Sie das Komponentenobjekt wie folgt:
export default {
props: {
label: { required: true, type: String },
done: { default: false, type: Boolean },
},
data() {
return {
isDone: this.done,
};
},
};
Vue macht hier ein bisschen Magie — es bindet alle Ihre Props direkt an die Komponenteninstanz, sodass wir nicht this.props.done
aufrufen müssen. Es bindet auch andere Attribute (data
, die Sie bereits gesehen haben, und andere wie methods
, computed
, etc.) direkt an die Instanz. Dies geschieht teilweise, um sie Ihrem Template zur Verfügung zu stellen. Der Nachteil ist, dass Sie die Schlüssel über diese Attribute hinweg eindeutig halten müssen. Dies ist der Grund, warum wir unser data
Attribut isDone
statt done
genannt haben.
Nun müssen wir die isDone
Eigenschaft an unsere Komponente anhängen. In ähnlicher Weise, wie es Vue ermöglicht, {{}}
Ausdrücke zu verwenden, um JavaScript-Ausdrücke innerhalb von Templates anzuzeigen, hat Vue eine spezielle Syntax, um JavaScript-Ausdrücke an HTML-Elemente und Komponenten zu binden: v-bind
. Der v-bind
Ausdruck sieht so aus:
v-bind:attribute="expression"
Mit anderen Worten, Sie setzen ein Präfix auf das Attribut/Prop, das Sie binden möchten, mit v-bind:
. In den meisten Fällen können Sie eine Kurzform für die v-bind
Eigenschaft verwenden, indem Sie einfach ein Doppelpunkt als Präfix für das Attribut/Prop setzen. Daher funktioniert :attribute="expression"
genauso wie v-bind:attribute="expression"
.
Im Fall der Checkbox in unserer ToDoItem
Komponente können wir v-bind
verwenden, um die isDone
Eigenschaft mit dem checked
Attribut auf dem <input>
Element zu verknüpfen. Beide der folgenden Beispiele sind gleichwertig:
<input type="checkbox" id="todo-item" v-bind:checked="isDone" />
<input type="checkbox" id="todo-item" :checked="isDone" />
Sie können sich frei entscheiden, welche Methode Sie verwenden möchten. Es ist jedoch am besten, es konsistent zu halten. Da die Kurzform häufiger verwendet wird, bleibt dieses Tutorial diesem Muster treu.
Also, lassen Sie uns dies tun. Aktualisieren Sie Ihr <input>
Element jetzt, um :checked="isDone"
aufzunehmen.
Testen Sie Ihre Komponente, indem Sie :done="true"
zum ToDoItem
Aufruf in App.vue
hinzufügen. Beachten Sie, dass Sie die v-bind
Syntax verwenden müssen, da ansonsten true
als String übergeben wird. Die angezeigte Checkbox sollte aktiviert sein.
<template>
<div id="app">
<h1>My To-Do List</h1>
<ul>
<li>
<to-do-item label="My ToDo Item" :done="true"></to-do-item>
</li>
</ul>
</div>
</template>
Versuchen Sie, true
auf false
zu ändern und wieder zurück, und laden Sie Ihre App zwischendurch neu, um zu sehen, wie sich der Zustand ändert.
Todos eine eindeutige ID geben
Super! Wir haben jetzt eine funktionierende Checkbox, bei der wir den Zustand programmgesteuert festlegen können. Derzeit können wir jedoch nur eine ToDoList
Komponente auf die Seite hinzufügen, da die id
festgecodet ist. Dies würde bei Hilfstechnologien zu Fehlern führen, da die id
benötigt wird, um Labels korrekt mit ihren Checkboxen zu verbinden. Um dies zu beheben, können wir die id
programmgesteuert in den Komponentendaten setzen.
Wir können die Methode Crypto.randomUUID()
verwenden, um einen eindeutigen String zu generieren und damit die id
s der Komponenten eindeutig zu halten. randomUUID()
ist in modernen Browsern integriert und bietet eine einfache Möglichkeit, die Einzigartigkeit zu gewährleisten, ohne auf externe Bibliotheken zurückzugreifen.
Fügen Sie als nächstes ein id
Feld zur data
Eigenschaft hinzu, wie unten gezeigt; hierbei wird crypto.randomUUID()
verwendet, um einen eindeutigen String zurückzugeben, dem wir dann todo-
als Präfix hinzufügen:
export default {
props: {
label: { required: true, type: String },
done: { default: false, type: Boolean },
},
data() {
return {
isDone: this.done,
id: "todo-" + crypto.randomUUID(),
};
},
};
Als nächstes binden Sie die id
sowohl an das id
Attribut der Checkbox als auch an das for
Attribut des Labels, und aktualisieren Sie die vorhandenen id
und for
Attribute, wie gezeigt:
<template>
<div>
<input type="checkbox" :id="id" :checked="isDone" />
<label :for="id">{{ label }}</label>
</div>
</template>
Zusammenfassung
Das war's für diesen Artikel. An diesem Punkt haben wir eine gut funktionierende ToDoItem
Komponente, die ein Label zur Anzeige übergeben bekommt, ihren überprüften Zustand speichert und jedes Mal mit einer eindeutigen id
gerendert wird, wenn sie aufgerufen wird. Sie können überprüfen, ob die eindeutigen id
s funktionieren, indem Sie vorübergehend mehr <to-do-item></to-do-item>
Aufrufe in App.vue
hinzufügen und dann deren gerenderten Output mit den DevTools Ihres Browsers überprüfen.
Jetzt sind wir bereit, mehrere ToDoItem
Komponenten zu unserer App hinzuzufügen. Im nächsten Artikel schauen wir uns an, wie man eine Menge von To-Do-Elementdaten zu unserer App.vue
Komponente hinzufügt, die wir dann durchlaufen und innerhalb von ToDoItem
Komponenten mit der v-for
Direktive anzeigen.