Standardmäßig erfolgt die Kommunikation zwischen Vue-Komponenten über Props. Props sind Eigenschaften, die von einer Elternkomponente an eine Kindkomponente weitergegeben werden. Hier ist zum Beispiel eine Komponente, bei der title eine Prop ist.
<blog-post title="My journey with Vue"></blog-post>
Props werden immer von der Elternkomponente an die Kindkomponente übergeben. Wenn Ihre Anwendung komplexer wird, stoßen Sie langsam auf das, was als Prop-Drilling bezeichnet wird. Hier ist ein verwandter Artikel, der auf React ausgerichtet ist, aber durchaus zutreffend ist). Prop-Drilling ist die Idee, Props nach unten und nach unten und nach unten an Kindkomponenten weiterzugeben – und, wie Sie sich vorstellen können, ist dies im Allgemeinen ein mühsamer Prozess.
Mühsames Prop-Drilling kann also ein potenzielles Problem in einer komplexen Anwendung sein. Das andere hat mit der Kommunikation zwischen *unabhängigen* Komponenten zu tun. Wir können all dies durch die Nutzung eines Event-Bus lösen.
Was ist ein Event-Bus? Nun, das steckt schon im Namen. Es ist eine Art Transportmittel für eine Komponente, um Props von einer Komponente an eine andere zu übergeben, egal wo sich diese Komponenten im Baum befinden.
Übungsaufgabe: Einen Zähler bauen
Lassen Sie uns gemeinsam etwas bauen, um das Konzept eines Event-Bus zu demonstrieren. Ein Zähler, der einen eingegebenen Wert addiert oder subtrahiert und die Gesamtsumme tallyt, ist ein guter Ausgangspunkt.
Sehen Sie den Pen Vuejs Event Bus Counter von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.
Um einen Event-Bus zu nutzen, müssen wir ihn zuerst wie folgt initialisieren:
import Vue from 'vue';
const eventBus = new Vue();
Dies setzt eine Instanz von Vue auf eventBus. Sie können es beliebig benennen. Wenn Sie eine Single-File-Komponente verwenden, sollten Sie diesen Snippet in einer separaten Datei ablegen, da Sie die Vue-Instanz, die eventBus zugewiesen ist, ohnehin exportieren müssen.
import Vue from 'vue';
export const eventBus = new Vue();
Wenn das erledigt ist, können wir ihn in unserer Zählerkomponente verwenden.
Hier ist, was wir tun wollen:
- Wir möchten eine Zählung mit einem Anfangswert von 0 haben.
- Wir möchten ein Eingabefeld, das numerische Werte akzeptiert.
- Wir möchten zwei Schaltflächen: eine, die den eingegebenen numerischen Wert beim Klicken zur Zählung hinzufügt, und die andere, die diesen eingegebenen numerischen Wert von der Zählung subtrahiert, wenn sie geklickt wird.
- Wir möchten eine Bestätigung dessen, was passiert ist, wenn sich die Zählung ändert.
So sieht die Vorlage mit all diesen Elementen aus:
<div id="app">
<h2>Counter</h2>
<h2>{{ count }}</h2>
<input type="number" v-model="entry" />
<div class="div__buttons">
<button class="incrementButton" @click.prevent="handleIncrement">
Increment
</button>
<button class="decrementButton" @click.prevent="handleDecrement">
Decrement
</button>
</div>
<p>{{ text }}</p>
</div>
Wir binden das Eingabefeld an einen Wert namens entry, den wir verwenden werden, um die Zählung entweder zu erhöhen oder zu verringern, je nachdem, was der Benutzer eingibt. Wenn eine der Schaltflächen geklickt wird, lösen wir eine Methode aus, die den Wert von count entweder erhöhen oder verringern sollte. Schließlich ist dieses {{ text }}-Ding im <p>-Tag die Nachricht, die wir ausgeben, um die Änderung der Zählung zusammenzufassen.
So fügt sich das alles in unserem Skript zusammen:
new Vue({
el: '#app',
data() {
return {
count: 0,
text: '',
entry: 0
}
},
created() {
eventBus.$on('count-incremented', () => {
this.text = `Count was increased`
setTimeout(() => {
this.text = '';
}, 3000);
})
eventBus.$on('count-decremented', () => {
this.text = `Count was decreased`
setTimeout(() => {
this.text = '';
}, 3000);
})
},
methods: {
handleIncrement() {
this.count += parseInt(this.entry, 10);
eventBus.$emit('count-incremented')
this.entry = 0;
},
handleDecrement() {
this.count -= parseInt(this.entry, 10);
eventBus.$emit('count-decremented')
this.entry = 0;
}
}
})
Sie haben vielleicht bemerkt, dass wir uns mit diesem Code auf den Event-Bus begeben.
Als Erstes müssen wir einen Pfad einrichten, um ein Ereignis von einer Komponente an eine andere zu senden. Diesen Pfad können wir mit eventBus.$emit() (wobei "emit" ein schickes Wort für das Aussenden ist) ebnen. Dieses Aussenden ist in zwei Methoden enthalten, handleIncrement und handleDecrement, die auf die Eingabeübermittlungen reagieren. Und sobald diese passieren, rastet unser Event-Bus zu jeder Komponente, die Daten anfordert, und sendet die Props über.

Sie haben vielleicht bemerkt, dass wir beide Ereignisse im created()-Lifecycle-Hook mit eventBus.$on() abhören. Bei beiden Ereignissen müssen wir den String übergeben, der dem emittierten Ereignis entspricht. Dies ist wie eine Kennung für das jeweilige Ereignis und das, was eine Möglichkeit für eine Komponente schafft, Daten zu empfangen. Wenn eventBus ein bestimmtes angekündigtes Ereignis erkennt, wird die folgende Funktion aufgerufen – und wir setzen einen Text, um anzuzeigen, was passiert ist, und lassen ihn nach drei Sekunden verschwinden.
Übungsaufgabe: Mehrere Komponenten verwalten
Nehmen wir an, wir arbeiten an einer Profilseite, auf der Benutzer ihren Namen und ihre E-Mail-Adresse für eine App aktualisieren und die Aktualisierung dann sehen können, ohne die Seite neu laden zu müssen. Dies kann reibungslos mit einem Event-Bus erreicht werden, obwohl wir dieses Mal mit zwei Komponenten zu tun haben: dem Benutzerprofil und dem Formular, das die Profiländerungen übermittelt.
Sehen Sie den Pen Vuejs Event Bus 2 von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.
Hier ist die Vorlage:
<div class="container">
<div id="profile">
<h2>Profile</h2>
<div>
<p>Name: {{name}}</p>
<p>Email: {{ email }}</p>
</div>
</div>
<div id="edit__profile">
<h2>Enter your details below:</h2>
<form @submit.prevent="handleSubmit">
<div class="form-field">
<label>Name:</label>
<input type="text" v-model="user.name" />
</div>
<div class="form-field">
<label>Email:</label>
<input type="text" v-model="user.email" />
</div>
<button>Submit</button>
</form>
</div>
</div>
Wir werden die ids (user.name und user.email) an die entsprechende Komponente übergeben. Zuerst richten wir die Vorlage für die Komponente "Edit Profile" (edit__profile) ein, die die Namen- und E-Mail-Daten enthält, die wir an die "Profile"-Komponente übergeben möchten, die wir als Nächstes einrichten. Wieder einmal haben wir einen Event-Bus eingerichtet, um diese Daten zu emittieren, nachdem er eine Übermittlungsereignis erkannt hat.
new Vue({
el: "#edit__profile",
data() {
return {
user: {
name: '',
email: ''
}
}
},
methods: {
handleSubmit() {
eventHub.$emit('form-submitted', this.user)
this.user = {}
}
}
})
Diese Daten werden verwendet, um das Profil des Benutzers in der "Profile"-Komponente (profile) reaktiv zu aktualisieren, die auf name und email wartet, wenn der Bus an ihrem Hub ankommt.
new Vue({
el: '#profile',
data() {
return {
name: '',
email: ''
}
},
created() {
eventHub.$on('form-submitted', ({ name, email}) => {
this.name = name;
this.email = email
})
}
})
Ihre Taschen sind gepackt. Jetzt müssen sie nur noch nach Hause gehen.
Ziemlich cool, oder? Auch wenn die Komponenten "Edit Profile" und "Profile" nicht zusammenhängen (oder keine direkte Eltern-Kind-Beziehung haben), ist es möglich, dass sie miteinander kommunizieren, verbunden durch dasselbe Ereignis.
Rollin’ right along
Ich habe Event-Bus in Fällen hilfreich gefunden, in denen ich Reaktivität in meiner App aktivieren möchte – insbesondere, um eine Komponente basierend auf der vom Server erhaltenen Antwort zu aktualisieren, ohne die Seite neu laden zu müssen. Es ist auch möglich, dass das emittierte Ereignis von mehr als einer Komponente abgehört werden kann.
Wenn Sie andere interessante Szenarien für die Verwendung eines Event-Bus haben, würde ich sie gerne in den Kommentaren erfahren. 🚌
Dies ist eine ziemlich einfache Situation. Was passiert, wenn eine neue Komponente angezeigt wird und dieselben Daten anzeigen muss? Sie müssen diesen Zustand für zukünftige Verbraucher beibehalten. Deshalb gibt es Dinge wie Vuex. Wenn Sie denken, dass Sie einen Event-Bus benötigen, ist es wahrscheinlich besser, mit Vuex zu beginnen.
„Dies ist eine ziemlich einfache Situation“ – Ich glaube, darin liegt die Nützlichkeit eines Event-Bus: einfache Situationen. Viele kleine Widgets und grundlegende Interaktionen können ohne den Overhead von Vuex durchgeführt werden. Ich habe jedoch einen Entwickler gesehen, der einen Event-Bus übermäßig genutzt und große Komplexität und Verwirrung geschaffen hat… Es geht also darum, zu lernen, welches Werkzeug für die jeweilige Aufgabe am besten geeignet ist.
Ich stimme zu, dass Entwickler in den meisten Fällen auf Vuex zurückgreifen sollten, um komplexe Zustände zu orchestrieren. Es gibt jedoch legitime Fälle, in denen Ereignisse an einen allgemeinen „Bus“ gesendet werden müssen. Zum Beispiel müssen Sie möglicherweise eine Bibliothek von Komponenten erstellen, ohne darin eine harte Abhängigkeit von Vuex zu schaffen. Wenn all diese Ereignisse eine Art standardisiertes Ereignis an diesen „Bus“ senden, haben sie effektiv eine Schnittstelle für jede Speicherstruktur geschaffen, die der Implementierer verwendet.
Ich bin jedoch etwas verwirrt von der Art und Weise, wie dies hier implementiert ist. Warum die ganze neue Vue-Instanz? Warum nicht einfach an die App-Wurzel senden?