Ereignisse aus einer Komponente
Die Einträge der Speisekarte haben jetzt Bestellen-Buttons, und die Bestellung steht in App.vue: die Ref bestellung und die Funktion zurBestellungHinzufuegen(id), die den Eintrag mit dieser id zur Bestellung hinzufügt oder einen weiteren davon, wenn er schon darin ist. Aber die Buttons sind in MenueEintrag, und eine Komponente kann die Daten ihres Elternteils nicht ändern: Sie hat bestellung nicht, und ihre Props sind schreibgeschützt.
Also teilt die Komponente ihrem Elternteil mit einem Ereignis mit, dass etwas passiert ist, so wie dir ein Button mit click einen Klick meldet. Sie deklariert ihre Ereignisse mit defineEmits, das wie defineProps keinen Import braucht. Und sie sendet eines mit der Funktion, die defineEmits zurückgibt und die meist emit heißt:
<script setup>
defineProps({
eintrag: { type: Object, required: true },
});
const emit = defineEmits(["bestellen"]);
</script>
<template>
<li class="eintrag">
<span>{{ eintrag.name }}</span>
<button @click="emit('bestellen', eintrag.id)">Bestellen</button>
</li>
</template>emit('bestellen', eintrag.id) sendet das Ereignis bestellen (Vue sagt, die Komponente emittiert es) mit einem Wert, der id des Eintrags. Der Elternteil hört darauf wie auf jedes andere Ereignis, mit @:
<MenueEintrag v-for="eintrag in menue" :key="eintrag.id" :eintrag="eintrag" @bestellen="zurBestellungHinzufuegen" />Kommt das Ereignis, ruft Vue zurBestellungHinzufuegen mit dem Wert des Ereignisses auf, also ist id die id des Eintrags, dessen Button angeklickt wurde. Die Komponente weiß nicht, was der Elternteil damit macht. Sie sagt nur „dieser Eintrag wurde bestellt“, und der Elternteil entscheidet, was passiert.
emit funktioniert auch im Skript, zum Beispiel in einer Funktion, die der Button aufruft. Im Skript stehen die Props in dem Objekt, das defineProps zurückgibt:
const props = defineProps({
eintrag: { type: Object, required: true },
});
const emit = defineEmits(["bestellen"]);
function bestellen() {
emit("bestellen", props.eintrag.id);
}Typische Fehler:
- Ein Ereignis, auf das der Elternteil unter einem anderen Namen hört, zum Beispiel
@bestelltfüremit('bestellen'), kommt nie an. Es passiert nichts, und die Konsole sagt auch nichts, prüfe also, ob die Namen übereinstimmen. - Ein Ereignis, das in
defineEmitsfehlt, funktioniert trotzdem, aber wenn die Komponente es sendet, warnt Vue:[Vue warn]: Component emitted event "bestellen" but it is neither declared in the emits option nor as an "onBestellen" prop.Deklariere jedes Ereignis: Die Liste sagt jedem, der die Komponente liest, was sie sagen kann.
So schreibst du es:
Anweisungen
- 1
Deklariere in
MenueEintrag.vuedas Ereignisbestellenund sende es mit deriddes Eintrags, wenn der Button Bestellen angeklickt wird. - 2
Höre in
App.vueauf das Ereignis beiMenueEintragund behandle es mitzurBestellungHinzufuegen. Bestelle einen Cappuccino und zwei Karottenkuchen: Die Bestellung zeigtCappuccino ×1undKarottenkuchen ×2.