Skip to content

Kapitel 17: Komponenten-Kommunikation (Teil 2) - Emits

📙 Lernziel: Daten von Kind- zu Eltern-Komponente mit defineEmits() übergeben!


17.1 Was sind Emits?

Emits (Events) senden Daten von Kind- zu Eltern-Komponente.

Datenfluss: Kind → Eltern (umgekehrt zu Props!)

Beispiel-Szenario:

App.vue (Eltern)
  └─ MyButton.vue (Kind)
       Sendet: click-Event mit Daten

17.2 Emits definieren (defineEmits())

In Vue 3 (<script setup>):

vue
<!-- components/MyButton.vue -->
<script setup>
// Emits definieren (mit TypeScript)
defineEmits<{
  (e: 'click', payload: string): void
  (e: 'submit'): void
}>()

// Oder ohne TypeScript (Runtime-Validierung)
defineEmits({
  click: [value: string],  // Mit Payload
  submit: null           // Ohne Payload
})
</script>

<template>
  <button @click="$emit('click', 'Hallo von Kind!')">
    Klick mich!
  </button>
  
  <button @click="$emit('submit')">
    Absenden
  </button>
</template>

<style scoped>
button {
  padding: 10px 20px;
  background: #42b883;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
</style>

17.3 Emits abhören (Eltern-Komponente)

Verwendung in Eltern-Komponente:

vue
<!-- App.vue -->
<script setup>
import MyButton from './components/MyButton.vue'

const handleClick = (message) => {
  alert('Vom Kind erhalten: ' + message)
}

const handleSubmit = () => {
  console.log('Formular abgesendet!')
}
</script>

<template>
  <div>
    <h1>Meine App</h1>
    
    <!-- Emit abhören (v-on:@) -->
    <MyButton @click="handleClick" @submit="handleSubmit" />
    
    <!-- Mit Inline-Funktion -->
    <MyButton 
      @click="(msg) => console.log(msg)" 
      @submit="() => console.log('Submit')" 
    />
  </div>
</template>

Wichtig:

  • @click = Event-Listener für click Emit
  • ✅ Payload wird als Parameter übergeben

17.4 v-model mit Komponenten

v-model in Komponenten = props + emit Kombination:

vue
<!-- components/CustomInput.vue -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
  <input 
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

Verwendung:

vue
<script setup>
import CustomInput from './components/CustomInput.vue'
import { ref } from 'vue'

const name = ref('')
</script>

<template>
  <div>
    <CustomInput v-model="name" />
    <p>Name: {{ name }}</p>
  </div>
</template>

Vue 3 Shorthand:

vue
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
  <!-- Einfacher -->
  <input 
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

17.5 Mehrere v-model bindungen

Vue 3 unterstützt mehrere v-model:

vue
<!-- components/UserForm.vue -->
<script setup>
defineProps(['name', 'email'])
defineEmits(['update:name', 'update:email'])
</script>

<template>
  <div>
    <input 
      :value="name"
      @input="$emit('update:name', $event.target.value)"
      placeholder="Name"
    />
    <input 
      :value="email"
      @input="$emit('update:email', $event.target.value)"
      placeholder="Email"
    />
  </div>
</template>

Verwendung:

vue
<script setup>
import UserForm from './components/UserForm.vue'
import { ref } from 'vue'

const userName = ref('')
const userEmail = ref('')
</script>

<template>
  <UserForm 
    v-model:name="userName"
    v-model:email="userEmail"
  />
  <p>Name: {{ userName }}, Email: {{ userEmail }}</p>
</template>

17.6 Übung: Counter-Komponente

Aufgabe: Erstelle eine Counter.vue Komponente mit Emit.

Lösung:

vue
<!-- components/Counter.vue -->
<script setup>
import { ref } from 'vue'

const count = ref(0)

defineEmits(['update:count', 'reset'])

const increment = () => {
  count.value++
  emit('update:count', count.value)
}

const decrement = () => {
  count.value--
  emit('update:count', count.value)
}

const reset = () => {
  count.value = 0
  emit('reset')
}
</script>

<template>
  <div class="counter">
    <h3>Zähler: {{ count }}</h3>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="reset">Zurücksetzen</button>
  </div>
</template>

<style scoped>
.counter {
  border: 1px solid #ddd;
  padding: 15px;
  margin: 10px;
  max-width: 300px;
}

button {
  margin: 0 5px;
  padding: 5px 10px;
}
</style>

Verwendung in App.vue:

vue
<script setup>
import Counter from './components/Counter.vue'
import { ref } from 'vue'

const currentCount = ref(0)

const handleReset = () => {
  console.log('Zähler wurde zurückgesetzt!')
}
</script>

<template>
  <Counter 
    v-model:count="currentCount"
    @reset="handleReset"
  />
  <p>Aktueller Zählerwert: {{ currentCount }}</p>
</template>

✅ Zusammenfassung

In diesem Kapitel hast du gelernt:

  • ✅ Was Emits sind (Kind → Eltern)
  • defineEmits() nutzen
  • ✅ Emits abhören (@event)
  • v-model mit Komponenten
  • ✅ Mehrere v-model bindungen
  • ✅ Praxis: Counter.vue Komponente

🎯 Nächster Schritt: In Kapitel 18 lernst du provide/inject - Vorfahren → Nachkommen!


← Zurück zu Kapitel 16: PropsWeiter zu Kapitel 18: Provide & Inject →

Frei für alle Anfänger