Hinzufügen eines neuen To-Do-Formulars: Vue-Ereignisse, Methoden und Modelle
Wir haben nun Beispieldaten bereitgestellt und eine Schleife, die jedes Datenstück nimmt und es in einem ToDoItem
in unserer App rendert. Was wir als Nächstes wirklich brauchen, ist die Möglichkeit, unseren Benutzern zu erlauben, ihre eigenen To-Do-Elemente in die App einzugeben. Dafür benötigen wir ein Text-<input>
, ein Ereignis, das ausgelöst wird, wenn die Daten übermittelt werden, eine Methode, die bei der Übermittlung ausgelöst wird, um die Daten hinzuzufügen und die Liste neu zu rendern, sowie ein Modell zur Steuerung der Daten. Das werden wir in diesem Artikel behandeln.
Voraussetzungen: |
Vertrautheit mit den grundlegenden HTML, CSS und JavaScript Sprachen, Kenntnisse über das Terminal/Befehlszeile. Vue-Komponenten werden als Kombination von JavaScript-Objekten geschrieben, die die Daten der App verwalten, und einer HTML-basierten Templatesyntax, die auf die zugrunde liegende DOM-Struktur abbildet. Für die Installation und um einige der fortgeschritteneren Funktionen von Vue zu nutzen (wie Single File Components oder Renderfunktionen), benötigen Sie ein Terminal mit installiertem Node + npm. |
---|---|
Ziel: | Erlernen, wie Formulare in Vue behandelt werden, und im weiteren Sinne, Ereignisse, Modelle und Methoden. |
Erstellen eines neuen To-Do-Formulars
Wir haben nun eine App, die eine Liste von To-Do-Elementen anzeigt. Allerdings können wir unsere Liste nicht aktualisieren, ohne unseren Code manuell zu ändern! Lassen Sie uns das beheben. Erstellen wir eine neue Komponente, die es uns ermöglicht, ein neues To-Do-Element hinzuzufügen.
-
Erstellen Sie in Ihrem Komponentenordner eine neue Datei namens
ToDoForm.vue
. -
Fügen Sie wie zuvor einen leeren
<template>
- und einen<script>
-Tag hinzu:vue<template></template> <script> export default {}; </script>
-
Fügen wir ein HTML-Formular hinzu, das es Ihnen ermöglicht, ein neues To-Do-Element einzugeben und in die App zu übermitteln. Wir benötigen ein
<form>
mit einem<label>
, einem<input>
und einem<button>
. Aktualisieren Sie Ihr Template wie folgt:vue<template> <form> <label for="new-todo-input"> What needs to be done? </label> <input type="text" id="new-todo-input" name="new-todo" autocomplete="off" /> <button type="submit">Add</button> </form> </template>
So haben wir nun eine Formular-Komponente, in die wir den Titel eines neuen To-Do-Elements eingeben können (dies wird später zu einem Label für das entsprechende
ToDoItem
, wenn es schließlich gerendert wird). -
Laden wir diese Komponente in unsere App. Gehen Sie zurück zu
App.vue
und fügen Sie die folgendeimport
-Anweisung direkt unter der vorherigen in Ihr<script>
-Element ein:jsimport ToDoForm from "./components/ToDoForm.vue";
-
Sie müssen die neue Komponente auch in Ihrer
App
-Komponente registrieren — aktualisieren Sie diecomponents
-Eigenschaft des Komponenten-Objekts, sodass sie so aussieht:jscomponents: { ToDoItem, ToDoForm, }
-
Abschließend für diesen Abschnitt, rendern Sie Ihre
ToDoForm
-Komponente in Ihrer App, indem Sie das<to-do-form />
-Element in das<template>
IhrerApp
einfügen, wie folgt:vue<template> <div id="app"> <h1>My To-Do List</h1> <to-do-form></to-do-form> <ul> <li v-for="item in ToDoItems" :key="item.id"> <to-do-item :label="item.label" :done="item.done" :id="item.id"></to-do-item> </li> </ul> </div> </template>
Jetzt sollten Sie beim Betrachten Ihrer laufenden Seite das neue Formular angezeigt sehen.
Wenn Sie es ausfüllen und auf die Schaltfläche "Hinzufügen" klicken, sendet die Seite das Formular zurück an den Server, aber das ist nicht wirklich, was wir wollen. Wir möchten tatsächlich eine Methode beim submit
-Ereignis ausführen, die das neue Todo zur ToDoItem
-Datenliste hinzufügt, die in App
definiert ist. Dazu müssen wir der Komponenteninstanz eine Methode hinzufügen.
Erstellen einer Methode und deren Bindung an ein Ereignis mit v-on
Um eine Methode in der ToDoForm
-Komponente verfügbar zu machen, müssen wir sie dem Komponentenobjekt hinzufügen, und dies geschieht in einer methods
-Eigenschaft unserer Komponente, die an derselben Stelle wie data()
, props
usw. eingefügt wird. Die methods
-Eigenschaft enthält alle Methoden, die wir in unserer Komponente aufrufen müssen. Wenn sie referenziert werden, werden Methoden vollständig ausgeführt, daher ist es keine gute Idee, sie zur Anzeige von Informationen im Template zu verwenden. Zum Anzeigen von Daten, die aus Berechnungen stammen, sollten Sie eine computed
-Eigenschaft verwenden, die wir später behandeln werden.
-
In dieser Komponente müssen wir eine
onSubmit()
-Methode zu einermethods
-Eigenschaft imToDoForm
-Komponentenobjekt hinzufügen. Wir werden dies verwenden, um die Übermittlungsaktion zu behandeln.Fügen Sie dies so hinzu:
jsexport default { methods: { onSubmit() { console.log("form submitted"); }, }, };
-
Als Nächstes müssen wir die Methode an den
submit
-Ereignishandler des<form>
-Elements binden. Wie Vue dasv-bind
-Syntax zum Binden von Attributen verwendet, hat Vue auch eine spezielle Direktive zur Ereignisbehandlung:v-on
. Diev-on
-Direktive arbeitet über diev-on:event="method"
-Syntax. Und ähnlich wiev-bind
gibt es auch eine Verkürzungssyntax:@event="method"
.Wir werden hier die Verkürzungssyntax verwenden, um Konsistenz zu bewahren. Fügen Sie den
submit
-Handler wie folgt zu Ihrem<form>
-Element hinzu:vue<form @submit="onSubmit">…</form>
-
Wenn Sie dies ausführen, sendet die App weiterhin die Daten an den Server, was zu einer Aktualisierung der Seite führt. Da wir alle unsere Verarbeitung auf dem Client durchführen, gibt es keinen Server, um den Postback zu bearbeiten. Wir verlieren auch alle lokalen Zustände bei der Seitenaktualisierung. Um zu verhindern, dass der Browser auf den Server postet, müssen wir die Standardaktion des Ereignisses stoppen, während es durch die Seite aufsteigt (
Event.preventDefault()
, in Vanilla JavaScript). Vue hat eine spezielle Syntax namens Ereignismodifikatoren, die das direkt in unserem Template für uns erledigen kann.Modifikatoren werden am Ende eines Ereignisses mit einem Punkt angehängt, wie folgt:
@event.modifier
. Hier ist eine Liste von Ereignismodifikatoren:.stop
: Stoppt die Ausbreitung des Ereignisses. EntsprichtEvent.stopPropagation()
in regulären JavaScript-Ereignissen..prevent
: Verhindert das Standardverhalten des Ereignisses. EntsprichtEvent.preventDefault()
..self
: Löst den Handler nur aus, wenn das Ereignis von diesem genauen Element gesendet wurde.{.key}
: Löst den Ereignishandler nur über die angegebene Taste aus. MDN hat eine Liste gültiger Tastenkombinationen; mehrwortige Tasten müssen einfach in kebab-case konvertiert werden (z. B.page-down
)..native
: Lauscht auf ein natives Ereignis am Root-Element (äußerst umschließendes) Ihrer Komponente..once
: Lauscht auf das Ereignis, bis es einmal ausgelöst wurde, und dann nicht mehr..left
: Löst den Handler nur über das linke Maustasten-Ereignis aus..right
: Löst den Handler nur über das rechte Maustastenereignis aus..middle
: Löst den Handler nur über das mittlere Maustastenereignis aus..passive
: Entspricht der Verwendung des{ passive: true }
-Parameters beim Erstellen eines Ereignis-Hörers in Vanilla JavaScript mithilfe vonaddEventListener()
.
In diesem Fall müssen wir den
.prevent
-Modifikator verwenden, um die Standardübermittlungsaktion des Browsers zu stoppen. Fügen Sie.prevent
dem@submit
-Handler in Ihrem Template wie folgt hinzu:vue<form @submit.prevent="onSubmit">…</form>
Wenn Sie jetzt versuchen, das Formular zu übermitteln, werden Sie feststellen, dass die Seite nicht neu geladen wird. Wenn Sie die Konsole öffnen, können Sie die Ergebnisse des console.log()
sehen, das wir in unserer onSubmit()
-Methode hinzugefügt haben.
Binden von Daten an Eingaben mit v-model
Als Nächstes benötigen wir eine Möglichkeit, den Wert aus dem <input>
des Formulars zu erhalten, damit wir das neue To-Do-Element zu unserer ToDoItems
-Datenliste hinzufügen können.
Das Erste, was wir benötigen, ist eine data
-Eigenschaft in unserem Formular, um den Wert des To-Do zu verfolgen.
-
Fügen Sie eine
data()
-Methode zu unseremToDoForm
-Komponentenobjekt hinzu, die einlabel
-Feld zurückgibt. Wir können den Anfangswert deslabel
auf eine leere Zeichenfolge setzen.Ihr Komponentenobjekt sollte nun ungefähr so aussehen:
jsexport default { methods: { onSubmit() { console.log("form submitted"); }, }, data() { return { label: "", }; }, };
-
Wir benötigen jetzt eine Möglichkeit, den Wert des
new-todo-input
-Elementfelds mit demlabel
-Feld zu verbinden. Vue hat dafür eine spezielle Direktive:v-model
.v-model
bindet sich an die von Ihnen festgelegte Dateneigenschaft und hält sie mit dem<input>
synchron.v-model
funktioniert über alle verschiedenen Eingabetypen, einschließlich Kontrollkästchen, Radios und Auswahlfelder. Umv-model
zu verwenden, fügen Sie ein Attribut mit der Strukturv-model="variable"
zu dem<input>
hinzu.In unserem Fall würden wir es zu unserem
new-todo-input
-Feld hinzufügen, wie unten zu sehen. Machen Sie das jetzt:vue<input type="text" id="new-todo-input" name="new-todo" autocomplete="off" v-model="label" />
Hinweis: Sie können Daten auch mit
<input>
-Werten über eine Kombination von Ereignissen undv-bind
-Attributen synchronisieren. Tatsächlich ist dies, wasv-model
im Hintergrund tut. Die genaue Ereignis- und Attributkombination variiert jedoch je nach Eingabetyp und erfordert mehr Code als die Verwendung derv-model
-Abkürzung. -
Testen wir unsere Verwendung von
v-model
, indem wir den Wert der imonSubmit()
-Method übermittelten Daten protokollieren. In Komponenten werden Dateneigenschaften mit dem Schlüsselwortthis
abgerufen. Daher greifen wir auf unserlabel
-Feld mitthis.label
zu.Aktualisieren Sie Ihre
onSubmit()
-Methode, um so auszusehen:jsmethods: { onSubmit() { console.log('Label value: ', this.label); } },
-
Gehen Sie nun zurück zu Ihrer laufenden App, fügen Sie dem
<input>
-Feld etwas Text hinzu und klicken Sie auf die Schaltfläche "Hinzufügen". Sie sollten den von Ihnen eingegebenen Wert in Ihrer Konsole sehen, zum Beispiel:Label value: My value
Ändern des v-model-Verhaltens mit Modifikatoren
In ähnlicher Weise wie bei Ereignismodifikatoren können wir auch Modifikatoren hinzufügen, um das Verhalten von v-model
zu ändern. In unserem Fall gibt es zwei, die wir berücksichtigen sollten. Der erste, .trim
, entfernt Leerzeichen vor oder nach der Eingabe. Wir können den Modifikator zu unserer v-model
-Anweisung wie folgt hinzufügen: v-model.trim="label"
.
Der zweite zu berücksichtigende Modifikator ist .lazy
. Dieser Modifikator ändert, wann v-model
den Wert für Texteingaben synchronisiert. Wie bereits erwähnt, funktioniert die v-model
-Synchronisation, indem die Variable über Ereignisse aktualisiert wird. Bei Texteingaben erfolgt diese Synchronisation über das input
-Ereignis. Oft bedeutet dies, dass Vue die Daten nach jedem Tastendruck synchronisiert. Der .lazy
-Modifikator führt dazu, dass v-model
stattdessen das change
-Ereignis verwendet. Dies bedeutet, dass Vue Daten nur synchronisiert, wenn die Eingabe den Fokus verliert oder das Formular übermittelt wird. Für unsere Zwecke ist dies viel sinnvoller, da wir nur die endgültigen Daten benötigen.
Um sowohl den .lazy
-Modifikator als auch den .trim
-Modifikator zusammen zu verwenden, können wir sie verketten, z. B.: v-model.lazy.trim="label"
.
Aktualisieren Sie Ihr v-model
-Attribut, um lazy
und trim
wie oben gezeigt zu verketten, und testen Sie dann Ihre App erneut. Versuchen Sie beispielsweise, einen Wert mit Leerzeichen an beiden Enden einzugeben.
Übergeben von Daten an Eltern mit benutzerdefinierten Ereignissen
Wir sind nun sehr nah dran, neue To-Do-Elemente zu unserer Liste hinzufügen zu können. Das Nächste, was wir tun müssen, ist, das neu erstellte To-Do-Element an unsere App
-Komponente zu übergeben. Dafür kann unsere ToDoForm
ein benutzerdefiniertes Ereignis auslösen, das die Daten übergibt, und App
kann darauf lauschen. Dies funktioniert ähnlich wie native Ereignisse bei HTML-Elementen: Eine Kindkomponente kann ein Ereignis auslösen, auf das über v-on
gehorcht werden kann.
Im Ereignishandler onSubmit
unseres ToDoForm
, fügen wir ein todo-added
-Ereignis hinzu. Benutzerdefinierte Ereignisse werden wie folgt ausgelöst: this.$emit("event-name")
. Es ist wichtig zu wissen, dass Ereignishandler Groß- und Kleinschreibung beachten und keine Leerzeichen enthalten können. Vue-Templates werden auch in Kleinbuchstaben umgewandelt, was bedeutet, dass Vue-Templates nicht auf Großbuchstaben-Ereignisse lauschen können.
-
Ersetzen Sie das
console.log()
in deronSubmit()
-Methode durch das Folgende:jsthis.$emit("todo-added");
-
Gehen Sie als Nächstes zurück zu
App.vue
und fügen Sie Ihrem Komponentenobjekt einemethods
-Eigenschaft hinzu, die eineaddToDo()
-Methode enthält, wie unten gezeigt. Vorläufig kann diese Methode einfachTo-do added
in die Konsole protokollieren.jsexport default { name: "app", components: { ToDoItem, ToDoForm, }, data() { return { ToDoItems: [ { id: "todo-" + nanoid(), label: "Learn Vue", done: false }, { id: "todo-" + nanoid(), label: "Create a Vue project with the CLI", done: true, }, { id: "todo-" + nanoid(), label: "Have fun", done: true }, { id: "todo-" + nanoid(), label: "Create a to-do list", done: false, }, ], }; }, methods: { addToDo() { console.log("To-do added"); }, }, };
-
Fügen Sie als Nächstes an
<to-do-form></to-do-form>
einen Ereignis-Listener für dastodo-added
-Ereignis hinzu, der dieaddToDo()
-Methode aufruft, wenn das Ereignis ausgelöst wird. Mit der@
-Abkürzung würde der Listener so aussehen:@todo-added="addToDo"
:vue<to-do-form @todo-added="addToDo"></to-do-form>
-
Wenn Sie Ihr
ToDoForm
übermitteln, sollten Sie das Konsolenprotokoll aus deraddToDo()
-Methode sehen. Das ist gut, aber wir übergeben noch keine Daten zurück an dieApp.vue
-Komponente. Das können wir tun, indem wir imToDoForm
-Komponente zusätzliche Argumente zurthis.$emit()
-Funktion übergeben.In diesem Fall möchten wir beim Auslösen des Ereignisses die
label
-Daten übergeben. Dies wird getan, indem Sie die Daten, die Sie übergeben wollen, als weiteren Parameter in diethis.$emit()
-Methode einfügen:this.$emit("todo-added", this.label)
. Das ist ähnlich, wie native JavaScript-Ereignisse Daten enthalten, außer dass benutzerdefinierte Vue-Ereignisse standardmäßig kein Ereignisobjekt haben. Das bedeutet, dass das ausgelöste Ereignis das Objekt direkt ohne Anpassungen erhält, die Sie übergeben. In unserem Fall wird unser Ereignisobjekt also nur eine Zeichenkette sein.Aktualisieren Sie Ihre
onSubmit()
-Methode wie folgt:jsexport default { // … methods: { // … onSubmit() { this.$emit("todo-added", this.label); }, // … }, // … };
-
Um diese Daten tatsächlich in
App.vue
abzurufen, müssen wir unsereraddToDo()
-Methode ein Parameter hinzufügen, das daslabel
des neuen To-Do-Elements enthält.Gehen Sie jetzt zurück zu
App.vue
und aktualisieren Sie dies:jsexport default { // … methods: { // … addToDo(toDoLabel) { console.log("To-do added:", toDoLabel); }, // … }, // … };
Wenn Sie Ihr Formular erneut testen, sehen Sie den Text, den Sie bei der Einreichung in Ihrer Konsole eingeben. Vue übergibt automatisch die Argumente, die nach dem Ereignisnamen in this.$emit()
kommen, an Ihren Ereignishandler.
Hinzufügen des neuen Todos zu unseren Daten
Jetzt, wo wir die Daten von ToDoForm
in App.vue
verfügbar haben, müssen wir ein Element erstellen, das es zur ToDoItems
-Array hinzufügt. Dies kann geschehen, indem wir ein neues To-Do-Elementobjekt mit unseren neuen Daten an das Array anhängen.
-
Aktualisieren Sie Ihre
addToDo()
-Methode wie folgt:jsexport default { // … methods: { // … addToDo(toDoLabel) { this.ToDoItems.push({ id: "todo-" + nanoid(), label: toDoLabel, done: false, }); }, // … }, // … };
-
Testen Sie Ihr Formular erneut, und Sie sollten sehen, dass neue To-Do-Elemente am Ende der Liste angehängt werden.
-
Lassen Sie uns eine weitere Verbesserung vornehmen, bevor wir weitermachen. Wenn Sie das Formular einreichen, während das Eingabefeld leer ist, werden To-Do-Elemente ohne Text trotzdem zur Liste hinzugefügt. Um das zu beheben, können wir verhindern, dass das todo-added-Ereignis ausgelöst wird, wenn der Name leer ist. Da der Name bereits durch den
.trim
-Modifikator getrimmt wird, müssen wir nur auf die leere Zeichenfolge testen.Gehen Sie zurück zu Ihrer
ToDoForm
-Komponente und aktualisieren Sie dieonSubmit()
-Methode wie folgt. Wenn der label-Wert leer ist, lassen wir dastodo-added
-Ereignis nicht auslösen.jsexport default { // … methods: { // … onSubmit() { if (this.label === "") { return; } this.$emit("todo-added", this.label); }, // … }, // … };
-
Testen Sie Ihr Formular erneut. Jetzt können Sie keine leeren Elemente mehr zur To-Do-Liste hinzufügen.
Verwenden von v-model, um einen Eingabewert zu aktualisieren
Es gibt noch eine Sache, die in unserer ToDoForm
-Komponente behoben werden muss – nach dem Absenden enthält das <input>
immer noch den alten Wert. Aber das ist leicht zu beheben – da wir v-model
verwenden, um die Daten an das <input>
in ToDoForm
zu binden, wird das Eingabefeld auch aktualisiert, wenn wir den Namen auf eine leere Zeichenfolge setzen.
Aktualisieren Sie Ihre onSubmit()
-Methode der ToDoForm
-Komponente so:
export default {
// …
methods: {
// …
onSubmit() {
if (this.label === "") {
return;
}
this.$emit("todo-added", this.label);
this.label = "";
},
// …
},
// …
};
Nun, wenn Sie auf die Schaltfläche "Hinzufügen" klicken, wird sich die "new-todo-input" selbst leeren.
Zusammenfassung
Ausgezeichnet. Wir können jetzt To-Do-Elemente zu unserem Formular hinzufügen! Unsere App beginnt jetzt, sich interaktiv anzufühlen, aber ein Problem ist, dass wir deren Erscheinungsbild bisher völlig ignoriert haben. Im nächsten Artikel werden wir uns darauf konzentrieren, dies zu beheben und die verschiedenen Wege untersuchen, die Vue bereitstellt, um Komponenten zu stylen.