So übergeben Sie Daten zwischen Komponenten in Vue.js
Veröffentlicht: 2022-03-10Das Teilen von Daten über Komponenten hinweg ist eine der Kernfunktionalitäten von VueJS. Es ermöglicht Ihnen, ein modulareres Projekt zu entwerfen, Datenumfänge zu steuern und einen natürlichen Datenfluss in Ihrer App zu erstellen.
Wenn Sie nicht Ihre gesamte Vue-App in einer Komponente erstellen (was keinen Sinn ergeben würde), werden Sie auf Situationen stoßen, in denen Sie Daten zwischen Komponenten austauschen müssen.
Am Ende dieses Tutorials kennen Sie drei Möglichkeiten, dies zu erreichen.
- Verwendung von Requisiten, um Daten von Eltern zu Kindern zu teilen,
- Senden von benutzerdefinierten Ereignissen zum Teilen von Daten von Kind zu Eltern,
- Verwenden von Vuex zum Erstellen eines freigegebenen Zustands auf App-Ebene.
Okay – legen wir gleich los!
Erstellen einer App mit Nuxt
Mit Spotify können Ihre Freunde sehen, wozu Sie gerade jammen. Was wäre, wenn der Rest des Internets auch Ihren Algo-Rhythmus erfahren könnte? Erfahren Sie, wie Sie Ihre eigene App erstellen, um mit Vue.js und Nuxt das, was Sie gerade hören, auf Spotify zu teilen. Lesen Sie einen verwandten Artikel →
1. Verwenden von Requisiten zum Teilen von Daten von Eltern zu Kindern
VueJS-Requisiten sind die einfachste Möglichkeit, Daten zwischen Komponenten auszutauschen. Requisiten sind benutzerdefinierte Attribute, die wir einer Komponente geben können. Dann können wir in unserer Vorlage diesen Attributen Werte zuweisen und – BAM – wir übergeben Daten von einer übergeordneten an eine untergeordnete Komponente!
Nehmen wir zum Beispiel an, wir arbeiten an einer Benutzerprofilseite und möchten, dass eine untergeordnete Komponente eine Benutzernamen-Prop akzeptiert. Wir brauchen zwei Komponenten.
- Nennen wir die untergeordnete Komponente, die die Stütze akzeptiert,
AccountInfo.vue
. - Nennen wir die übergeordnete Komponente, die die Stütze übergibt,
ProfilePage.vue
.
Innerhalb AccountInfo.vue
können wir die akzeptierten Requisiten mit der Option props deklarieren. Lassen Sie es uns also in den Komponentenoptionen wie folgt aussehen.
// AccountInfo.vue <template> <div id='account-info'> {{username}} </div> </template> <script> export default { props: ['username'] } </script>
Um die Daten dann tatsächlich vom übergeordneten Element ( ProfilePage.vue
) zu übergeben, übergeben wir sie wie ein benutzerdefiniertes Attribut.
// ProfilePage.vue <account-info username='matt' />
Wenn wir jetzt unsere Seite laden, können wir sehen, dass unsere AccountInfo
Komponente den von ihrer übergeordneten Komponente übergebenen Wert korrekt wiedergibt.
Wie bei der Arbeit mit anderen VueJS-Direktiven können wir v-bind verwenden, um Props dynamisch zu übergeben. Nehmen wir zum Beispiel an, wir möchten die username prop so setzen, dass sie gleich einer Variablen ist. Wir können dies erreichen, indem wir die Kurzschrift für die v-bind-Direktive verwenden (oder einfach :
kurz). Der Code würde in etwa so aussehen:
<template> <div> <account-info :username="user.username" /> </div> </template> <script> import AccountInfo from "@/components/AccountInfo.vue"; export default { components: { AccountInfo }, data() { return { user: { username: 'matt' } } } } </script>
Das bedeutet, dass wir unsere Daten ändern können und alle untergeordneten Requisiten, die diesen Wert verwenden, ebenfalls aktualisiert werden.
Tipp: Überprüfen Sie immer Ihre Requisiten
Wenn Sie klareren Vue-Code schreiben möchten, ist es eine wichtige Technik, Ihre Requisiten zu überprüfen. Kurz gesagt bedeutet dies, dass Sie die Anforderungen an Ihre Requisite (dh Typ, Format usw.) angeben müssen. Wenn eine dieser Anforderungen nicht erfüllt ist (z. B. wenn der Requisite ein falscher Typ übergeben wird), druckt Vue eine Warnung aus.
Nehmen wir an, wir möchten, dass unsere Benutzernamen-Prop nur Zeichenfolgen akzeptiert. Wir müssten unser Props-Objekt so ändern, dass es so aussieht:
export default { props: { username: String } }
Das Verifizieren von Requisiten ist unerlässlich, wenn Sie in großen Vue-Apps arbeiten oder Plugins entwerfen. Es hilft sicherzustellen, dass alle auf derselben Seite sind und Requisiten so verwenden, wie sie beabsichtigt waren.
Für eine vollständige Liste der Überprüfungen, die wir in Requisiten aufnehmen können, würde ich definitiv empfehlen, die offizielle Dokumentation für eine eingehende Überprüfung zu lesen.
Tipp: Befolgen Sie die Namenskonventionen für Props
Gemäß dem VueJS-Styleguide ist der beste Weg, Ihre Requisiten zu benennen, die Verwendung von camelCase
, wenn Sie sie in Ihrem Skript deklarieren, und kebab-case, wenn Sie im Vorlagencode auf sie verweisen.
Die Begründung dahinter ist eigentlich ganz einfach. In Javascript ist camelCase
die Standard-Namenskonvention und in HTML ist es kebab-case.
Daher empfiehlt Vue, dass wir uns an die Normen jeder Sprache halten. Glücklicherweise ist Vue in der Lage, automatisch zwischen den beiden Stilen zu konvertieren, sodass Entwickler keine zusätzliche Einrichtung benötigen.
// GOOD <account-info :my-username="user.username" /> props: { myUsername: String } // BAD <account-info :myUsername="user.username" /> props: { "my-username": String }
2. Ausgeben von Ereignissen, um Daten vom Kind zum Elternteil zu teilen
Nun, da wir Daten haben, die die Hierarchie nach unten übergeben, lassen Sie uns sie in die andere Richtung weitergeben: von einer untergeordneten Komponente zu einer übergeordneten Komponente. Wir können keine Requisiten verwenden, aber wir können benutzerdefinierte Ereignisse und Listener verwenden.
Jede Vue-Instanz kann eine .$emit(eventName)
-Methode aufrufen, die ein Ereignis auslöst. Dann können wir auf dieses Ereignis auf die gleiche Weise wie auf jedes andere lauschen, indem wir die v-on-Direktive verwenden.
Erstellen eines benutzerdefinierten Ereignisses
Lassen Sie uns auf unserem Benutzerprofilbeispiel aufbauen, indem wir eine Schaltfläche hinzufügen, die den Benutzernamen ändert. Lassen Sie uns in unserer untergeordneten Komponente ( AccountInfo.vue
) die Schaltfläche erstellen.
Wenn dann auf diese Schaltfläche geklickt wird, geben wir ein Ereignis namens changeUsername
.
<template> <div id='account-info'> <button @click='changeUsername()'>Change Username</button> {{username}} </div> </template> <script> export default { props: { username: String }, methods: { changeUsername() { this.$emit('changeUsername') } } } </script>
Innerhalb des übergeordneten Elements verarbeiten wir dieses Ereignis und ändern die Variable user.username
. Wie wir bereits besprochen haben, können wir Ereignisse mit der v-on-Direktive oder kurz „@“ abhören.
<template> <div> <account-info :username="user.username" @changeUsername="user.username = 'new name'"/> </div> </template>
Probieren wir es aus. Wenn Sie auf die Schaltfläche klicken, sollten Sie sehen, dass sich der Benutzername in "neuer Name" ändert.
Tipp: Benutzerdefinierte Ereignisse können Argumente akzeptieren
Der häufigste Anwendungsfall für die Übergabe von Argumenten an Ihre Ereignisse ist, wenn Sie möchten, dass eine untergeordnete Komponente einen bestimmten Wert für ihre Eigenschaft festlegen kann. Sie möchten den Wert einer Requisite niemals direkt von der Komponente selbst aus bearbeiten.
Glücklicherweise können wir jedoch Pass-Argumente mit unseren benutzerdefinierten Ereignissen verwenden, um die Werte der übergeordneten Komponente zu ändern.
Angenommen, wir möchten das Ereignis changeUsername
ändern, damit wir ihm einen Wert übergeben können.
Die $emit
Methode akzeptiert einen optionalen zweiten Parameter für Argumente. Wir fügen also nur unseren neuen Benutzernamenswert nach dem Namen unserer Veranstaltung hinzu.
this.$emit('changeUsername', 'mattmaribojoc')
Dann können wir in unserer übergeordneten Komponente entweder inline auf diese Werte zugreifen, indem wir eine spezielle $event
Variable verwenden, oder wir können eine Handler-Methode schreiben, die einen Parameter akzeptiert.
<account-info :username="user.username" @changeUsername="user.username = $event"/> OR <account-info :username="user.username" @changeUsername="changeUsername($event)"/> export default { ... methods: { changeUsername (username) { this.user.username = username; } } }
3. Verwenden von Vuex zum Erstellen eines gemeinsamen Zustands auf Anwendungsebene
Okay – wir wissen, wie man Daten zwischen Eltern/Kindern teilt, aber was ist mit anderen Komponenten? Müssen wir ein extrem komplexes Hierarchiesystem aufbauen, wenn wir Daten weitergeben wollen?
Zum Glück nicht. Die wunderbare Vuex-Zustandsverwaltungsbibliothek vereinfacht das Leben von Entwicklern seit Jahren. Kurz gesagt, es entsteht ein zentraler Datenspeicher, auf den alle Komponenten zugreifen können.
In den zuvor verwendeten Methoden (Requisiten / Emittieren von Ereignissen) hat jede Komponente ihren eigenen Datenzustand, den wir dann zwischen den Komponenten teilen. Mit Vuex können wir jedoch alle gemeinsam genutzten Daten in einen einzigen Zustand extrahieren, auf den jede Komponente problemlos zugreifen kann. Dieser gemeinsam genutzte Zustand wird als Speicher bezeichnet.
Probieren wir es aus.
Da Vuex vom Kerncode von Vue getrennt ist, müssen wir es zuerst installieren und in unser Projekt importieren. Zuerst müssen wir npm install vuex --save
in unserer Projekt-CLI ausführen.
Erstellen Sie dann einen src/store-Ordner mit einer index.js-Datei, die den folgenden Code enthält.
// store/index.js import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export default new Vuex.Store({ state: {}, getters: {}, mutations: {}, actions: {} });
Um dies in unsere Root-Vue-Instanz aufzunehmen, müssen wir unsere store/index.js-Datei importieren und an unseren Vue-Konstruktor übergeben.
// main.js import store from "./store"; new Vue({ store, ...
Zugriff auf Vue Store Inside-Komponenten
Da wir unseren Vuex-Store zu unserer Root-Vue-Instanz hinzugefügt haben, wird er in alle untergeordneten Root-Instanzen injiziert. Wenn wir von einer Komponente aus auf den Store zugreifen möchten, können wir dies über this.$store
tun.
Lassen Sie uns nun auf die Besonderheiten jedes der vier Teile eines Vuec-Geschäfts eingehen.
1. Zustand
Der Vuex-Status ist ein Objekt, das Daten auf Anwendungsebene enthält. Alle Vue-Instanzen können auf diese Daten zugreifen.
Lassen Sie uns für unseren Shop ein Benutzerobjekt erstellen, das weitere Benutzerprofildaten speichert.
export default new Vuex.Store({ state: { user: { username: 'matt', fullName: 'Matt Maribojoc' } }, getters: {}, mutations: {}, actions: {} });
Wir können auf diese Daten in jeder Instanzkomponente wie dieser zugreifen.
mounted () { console.log(this.$store.state.user.username); },
2. Getter
Wir verwenden Vuex-Getter, um einen modifizierten Wert von Zustandsdaten zurückzugeben. Eine gute Möglichkeit, sich Getter vorzustellen, besteht darin, sie wie berechnete Eigenschaften zu behandeln. Beispielsweise speichern Getter wie berechnete Eigenschaften ihre Ergebnisse im Cache und werten sie nur dann neu aus, wenn eine Abhängigkeit geändert wird.
Nehmen wir an, wir bauen auf unserem früheren Geschäft auf und wollen eine Methode erstellen, die den Vornamen eines Benutzers basierend auf dem vollständigen Namensattribut zurückgibt.
getters: { firstName: state => { return state.user.fullName.split(' ')[0] } }
Vuex-Getter-Eigenschaften sind für Komponenten im store.getters
Objekt verfügbar.
mounted () { console.log(this.$store.getters.firstName); }
Tipp: Kennen Sie die Standard-Getter-Argumente
Standardmäßig akzeptieren Vuex-Getter zwei Argumente.
- state — das Zustandsobjekt für unsere Anwendung;
- getters – das store.getters-Objekt, was bedeutet, dass wir andere Getter in unserem Store aufrufen können.
Jeder Getter, den Sie deklarieren, erfordert das erste Zustandsargument. Und je nachdem, wie Sie Ihren Code entwerfen, können Ihre Getter mit dem zweiten „Getter“-Argument aufeinander verweisen.
Lassen Sie uns einen Nachnamen-Getter erstellen, der einfach unseren Vornamenswert aus unserer Statuseigenschaft für den vollständigen Namen entfernt. Dieses Beispiel würde sowohl das State- als auch das Getter-Objekt erfordern.
lastName (state, getters) { return state.user.fullName.replace(getters.firstName, ''); }
Tipp: Übergeben Sie benutzerdefinierte Argumente an Vuex-Getter
Ein weiteres cooles Feature von Gettern ist, dass wir ihnen benutzerdefinierte Argumente übergeben können, indem wir unseren Getter dazu bringen, eine Methode zurückzugeben.
prefixedName: (state, getters) => (prefix) => { return prefix + getters.lastName; } // in our component console.log(this.$store.getters.prefixedName("Mr."));
3. Mutationen
Mutationen sind die einzige Möglichkeit, den Wert des Zustandsobjekts richtig zu ändern. Ein wichtiges zu beachtendes Detail ist, dass Mutationen synchron sein müssen .
Wie Getter akzeptieren Mutationen immer die Vuex-Zustandseigenschaft als erstes Argument. Sie akzeptieren auch ein benutzerdefiniertes Argument – Payload genannt – als zweites Argument.
Nehmen wir beispielsweise eine Mutation vor, um den Namen eines Benutzers in einen bestimmten Wert zu ändern.
mutations: { changeName (state, payload) { state.user.fullName = payload } },
Dann können wir diese Methode von unserer Komponente mit der Methode store.commit
, mit unserer Nutzlast als zweitem Argument.
this.$store.commit("changeName", "New Name");
In den meisten Fällen möchten Sie, dass Ihre Nutzlast ein Objekt ist. Dies bedeutet nicht nur, dass Sie mehrere Argumente an eine Mutation übergeben können, sondern macht Ihren Code aufgrund der Eigenschaftsnamen in Ihrem Objekt auch lesbarer.
changeName (state, payload) { state.user.fullName = payload.newName }
Es gibt zwei verschiedene Möglichkeiten, Mutationen mit einer Payload aufzurufen.
- Sie können den Mutationstyp als erstes Argument und die Nutzdaten als zweites haben.
- Sie können ein einzelnes Objekt übergeben deklarieren, mit einer Eigenschaft für den Typ und einer anderen für die Nutzlast.
this.$store.commit("changeName", { newName: "New Name 1", }); // or this.$store.commit({ type: "changeName", newName: "New Name 2" });
Es gibt keinen wirklichen Unterschied zwischen der Funktionsweise der beiden, also hängt es ganz von den persönlichen Vorlieben ab. Denken Sie daran, dass es immer am besten ist, während Ihres gesamten Projekts konsistent zu sein, also bleiben Sie dabei, egal für welches Sie sich entscheiden!
4. Aktionen
In Vuex sind Aktionen Mutationen ziemlich ähnlich, da wir sie verwenden, um den Zustand zu ändern. Aktionen ändern jedoch nicht die Werte selbst. Stattdessen begehen Aktionen Mutationen.
Außerdem müssen Vuex-Mutationen zwar synchron sein, Aktionen jedoch nicht. Mithilfe von Aktionen können wir zum Beispiel eine Mutation nach einem API-Aufruf aufrufen.
Während die meisten Vuex-Handler, die wir gesehen haben, den Status als Hauptparameter akzeptieren, akzeptieren Aktionen ein Kontextobjekt. Dieses Kontextobjekt ermöglicht uns den Zugriff auf die Eigenschaften in unserem Vuex-Speicher (z. B. Status, Commit, Getter).
Hier ist ein Beispiel für eine Vuex-Aktion, die zwei Sekunden wartet und dann die changeName
Mutation festschreibt.
actions: { changeName (context, payload) { setTimeout(() => { context.commit("changeName", payload); }, 2000); } }
Innerhalb unserer Komponenten verwenden wir die Methode store.dispatch, um unsere Funktion auszuführen. Wir übergeben Argumente genau wie bei Mutationen. Wir deklarieren den Typ und übergeben alle benutzerdefinierten Argumente im zweiten Argument.
this.$store.dispatch("changeName", { newName: "New Name from Action" });
Einpacken
Jetzt sollten Sie drei verschiedene Möglichkeiten kennen, um Daten über Komponenten in VueJS auszutauschen: Requisiten, benutzerdefinierte Ereignisse und einen Vuex-Speicher.
Ich hoffe, dieses Tutorial hat Ihnen geholfen, einen besseren Einblick in einige verschiedene Vue-Methoden und Best Practices zu erhalten. Lassen Sie mich wissen, wie Sie sie in Ihre Projekte implementiert haben!
Weiterführende Lektüre
Wenn Sie daran interessiert sind, noch tiefer in die technische Seite/Fähigkeiten jeder Technik einzusteigen, finden Sie hier einige großartige Ausgangspunkte.
- Vuex Official Guide-Website
- VueJS-Dokumente für Requisiten und benutzerdefinierte Ereignisse
- „WTF ist Vuex? Ein Leitfaden für Anfänger zum Anwendungsdatenspeicher von Vue“, Anthony Gore, Vue.js-Entwickler