VueJS-3-Tutorial – Kommunikation mit Events und defineEmits
geprüft am 2 September 2026 · 3 Min.
Eine Kindkomponente meldet der Elternkomponente eine Änderung, indem sie ein Event emittiert: defineEmits deklariert es, emit('add-to-cart', id) sendet es, und die Elternkomponente hört es mit @add-to-cart ab. Props gehen nach unten, Events nach oben.
Props gehen von der Eltern- zur Kindkomponente hinunter. Um eine Information nach oben zu geben, emittiert eine Komponente ein Event, und die Elternkomponente hört darauf, genau wie sie auf einen Klick hören würde.
Das Problem
Seit der Aufteilung aus Kapitel 8 lebt der Warenkorb in App.vue und der Button in ProductDisplay.vue. Das Kind kann cart nicht ändern: es hat keinen Zugriff darauf, und eine Komponente darf nicht in den Zustand einer anderen schreiben.
Die richtige Formulierung lautet nicht „das Kind legt in den Warenkorb“, sondern „das Kind meldet einen Klick, die Elternkomponente entscheidet, was daraus wird“.
Deklarieren und emittieren
Deklarier in der Kindkomponente die Events, die sie aussendet, und emittier dann:
<script setup>
const emit = defineEmits(['add-to-cart'])
function addToCart() {
emit('add-to-cart')
}
</script>
<template>
<button
class="button"
:class="{ disabledButton: !inStock }"
:disabled="!inStock"
@click="addToCart"
>
Ajouter au panier
</button>
</template>defineEmits ist wie defineProps ein Compiler-Makro: kein Import nötig. Es liefert die Funktion zurück, mit der emittiert wird.
Die Events zu deklarieren ist nicht Pflicht, aber sinnvoll: die Liste dokumentiert den Vertrag der Komponente, der Editor vervollständigt sie automatisch, und Vue warnt, wenn du einen nicht deklarierten Namen emittierst.
In der Elternkomponente zuhören
Ein eigenes Event hörst du mit derselben Syntax ab wie ein natives:
<script setup>
import { ref } from 'vue'
import ProductDisplay from './components/ProductDisplay.vue'
const cart = ref(0)
function updateCart() {
cart.value += 1
}
</script>
<template>
<div class="cart">Panier ({{ cart }})</div>
<ProductDisplay :premium="premium" @add-to-cart="updateCart" />
</template>Klick: der Zähler läuft wieder. Der Button steckt im Kind, der Zähler in der Elternkomponente, und keiner von beiden kennt den Zustand des anderen.
Daten mitgeben
Ein realistischer Warenkorb merkt sich, was hineinkommt, nicht nur wie viel. Gib die ID der Variante als zweites Argument an emit:
<script setup>
function addToCart() {
emit('add-to-cart', variants.value[selectedVariant.value].id)
}
</script>Die Elternkomponente bekommt sie als Parameter ihrer Funktion:
<script setup>
const cart = ref([])
function updateCart(id) {
cart.value.push(id)
}
</script>
<template>
<div class="cart">Panier ({{ cart.length }})</div>
<ProductDisplay :premium="premium" @add-to-cart="updateCart" />
</template>cart ist jetzt ein Array, die Anzeige nutzt deshalb cart.length. Leg das blaue T-Shirt mehrmals hinein und prüf in den Vue-Devtools, dass sich das Array tatsächlich mit 2234 füllt.
Für mehrere Informationen emittier lieber ein Objekt als eine lange Argumentliste:
emit('add-to-cart', { id: variant.id, taille: 'M', quantite: 1 })Die Namen der Events
Schreib den Namen in kebab-case: add-to-cart, nicht addToCart. HTML-Attribute unterscheiden keine Groß- und Kleinschreibung, ein direkt in einer Seite geschriebenes Template bekäme @addtocart, und der Listener würde nie auslösen. In einer .vue-Datei fängt Vue die Schreibweise ab, aber gewöhn es dir gleich richtig an.
Ein eigenes Event erreicht nur die direkte Elternkomponente. Liegen drei Komponentenebenen zwischen Sender und Empfänger, musst du es auf jeder Etage erneut emittieren. Sobald das lästig wird, ist es das Zeichen für einen geteilten Zustand: genau das ist die Aufgabe von Pinia.
Die Fließrichtung
Eine Bewertung, die auf diesem Weg ankommt, lässt sich anschließend beim Einblenden animieren.
Merk dir diese zwei Sätze: Props gehen nach unten, Events gehen nach oben. Die Elternkomponente besitzt die Daten, das Kind bittet um ihre Änderung. Das macht den Fluss vorhersehbar und den Ursprung einer Änderung jederzeit nachvollziehbar.
Events werden in der Option emits deklariert und mit this.$emit('add-to-cart', id) emittiert. Die Elternkomponente hört sie genau gleich ab.
remove-from-cart, das ein zweiter Button emittiert, und lass die Elternkomponente die letzte ID aus dem Array entfernen.Häufige Fehler
@addtocart, und der Listener würde nie auslösen. Nimm kebab-case.