Vue.js Components

6 Kernkonzepte
Fortgeschrittene Komponentenkonzepte in Vue.js: Props · Events · Slots · Composables · Dynamic Components · Provide / Inject Diese Cheatsheet vertieft die Komponentenkommunikation und -organisation in Vue.js – von Props und Events über Slots und Composables bis zu fortgeschrittenen Techniken wie Dynamic Components und Provide/Inject.

Props – Typisierung und Validierung

defineProps · type · required · default · validator
const props = defineProps({ name: { type: String, required: true }, age: { type: Number, default: 0 }, status: { validator: (value) => ['active', 'inactive'].includes(value) } });

Props sind Daten, die von einer Elternkomponente an eine Kindkomponente übergeben werden. Mit defineProps können Sie Typen, Standardwerte und Validierungsfunktionen definieren.

Prop-Typen

Typ Beschreibung
String Text
Number Zahl
Boolean Wahrheitswert
Array Liste
Object Objekt
Function Funktion
Promise Promise
null Beliebiger Typ (keine Prüfung)
Beispiele
<script setup>
const props = defineProps({
// Einfache Typdeklaration
message: String,
// Mit Standardwert
count: { type: Number, default: 0 },
// Erforderlich
user: { type: Object, required: true },
// Mit Validator
status: {
type: String,
validator: (value) => {
return ['active', 'inactive', 'pending'].includes(value);
}
},
// Boolean mit Default true
visible: { type: Boolean, default: true }
});
</script>
<!-- Verwendung -->
<Child :user="{ name: 'Anna', age: 30 }" status="active" count="5" />
Tipp: Nutzen Sie TypeScript mit Vue für noch bessere Typsicherheit: defineProps<{ name: string; age?: number }>(). Props sollten nie direkt in der Kindkomponente mutiert werden – verwenden Sie Events für die Kommunikation nach oben.

Events & v-model – Kommunikation nach oben

defineEmits · $emit · v-model · update:modelValue
const emit = defineEmits(['update', 'delete']); const model = defineModel({ type: String }); // Vue 3.4+ <Child @update="handleUpdate" /> <input @input="$emit('update:modelValue', $event.target.value)" />

Events ermöglichen die Kommunikation von der Kindkomponente zur Elternkomponente. defineEmits deklariert die Events. v-model ist eine syntaktische Zucker für die Zwei-Wege-Bindung.

Beispiele
<!-- Child.vue -->
<script setup>
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue', 'delete']);
// Vue 3.4+ mit defineModel
const model = defineModel({ type: String });
</script>
<template>
<!-- v-model mit defineModel (einfach) -->
<input v-model="model" />
<!-- v-model mit props/emit -->
<input
:value="props.modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
<button @click="$emit('delete', props.modelValue)">Löschen</button>
</template>
<!-- Parent.vue -->
<Child v-model="text" @delete="handleDelete" />
<!-- Mehrere v-model Bindungen (Vue 3) -->
<Child v-model:name="userName" v-model:age="userAge" />
Tipp: defineModel (ab Vue 3.4) vereinfacht die v-model-Implementierung erheblich. Für ältere Versionen verwenden Sie props und emit('update:modelValue').

Slots – Flexible Inhalte

<slot> · v-slot · #default · #named
// Child.vue <div class="card"> <header><slot name="header">Standard-Header</slot></header> <main><slot>Standard-Inhalt</slot></main> <footer><slot name="footer">Standard-Footer</slot></footer> </div>

Slots ermöglichen es, einer Komponente dynamische Inhalte zu übergeben. Benannte Slots (name) erlauben mehrere Einschubstellen. Scoped Slots geben Daten von der Kindkomponente an den Slot-Inhalt weiter.

Beispiele
<!-- Card.vue -->
<template>
<div class="card">
<slot name="header">
<h3>Standard-Header</h3>
</slot>
<div class="body">
<slot>Standard-Inhalt</slot>
</div>
<slot name="footer">
<small>Standard-Footer</small>
</slot>
</div>
</template>
<!-- Parent.vue (Verwendung) -->
<Card>
<template #header>
<h1>Benutzerprofil</h1>
</template>
<p>Informationen über den Benutzer.</p>
<template #footer>
<button>Bearbeiten</button>
</template>
</Card>
<!-- Scoped Slots (Daten von Kind an Parent) -->
<Child #default="{ item }">
{{ item }}
</Child>
Tipp: Scoped Slots (v-slot="{ item }") sind ideal für Listen- und Tabellenkomponenten, bei denen die Darstellung der Daten vom Elternteil gesteuert werden soll.

Composables – Logik wiederverwenden

useCounter · useFetch · useState
// composables/useCounter.js import { ref, computed } from 'vue'; export function useCounter(initialValue = 0) { const count = ref(initialValue); const double = computed(() => count.value * 2); function increment() { count.value++; } return { count, double, increment }; }

Composables sind Funktionen, die reaktive Logik kapseln und in mehreren Komponenten wiederverwendbar machen – ähnlich wie Hooks in React.

Beispiele
// composables/useFetch.js
import { ref, onMounted } from 'vue';
export function useFetch(url) {
const data = ref(null);
const loading = ref(false);
const error = ref(null);
async function fetchData() {
loading.value = true;
try {
const res = await fetch(url);
data.value = await res.json();
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
}
onMounted(fetchData);
return { data, loading, error, fetchData };
}
// In Komponente verwenden
import { useFetch } from './composables/useFetch';
const { data, loading, error } = useFetch('https://api.example.com/users');
Tipp: Composables sollten mit use beginnen (Konvention). Sie können andere Composables aufrufen und so komplexe Logik modular aufbauen. Nutzen Sie sie für API-Aufrufe, Formularvalidierung, Timer, usw.

Dynamische Komponenten – <component :is>

<component :is> · keep-alive
// Komponente dynamisch rendern <component :is="currentTab" /> // Mit keep-alive für Zustandserhaltung <keep-alive> <component :is="currentTab" /> </keep-alive>

Dynamische Komponenten erlauben das Austauschen von Komponenten zur Laufzeit – ideal für Tab-Navigation, modale Dialoge oder verschiedene Ansichten.

Beispiele
<!-- Tabs.vue -->
<script setup>
import TabA from './TabA.vue';
import TabB from './TabB.vue';
import TabC from './TabC.vue';
const tabs = { A: TabA, B: TabB, C: TabC };
const currentTab = ref('A');
</script>
<template>
<div class="tab-buttons">
<button
v-for="(tab, key) in tabs"
:key="key"
@click="currentTab = key"
:class="{ active: currentTab === key }"
>Tab {{ key }}</button>
</div>
<!-- Dynamische Komponente -->
<keep-alive>
<component :is="tabs[currentTab]" />
</keep-alive>
</template>
<!-- Async Component -->
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
);
Tipp: <keep-alive> bewahrt den Zustand von Komponenten, wenn sie nicht aktiv sind – nützlich für Tabs oder Schritt-für-Schritt-Formulare. Async Components werden erst geladen, wenn sie benötigt werden (Lazy Loading).

Provide / Inject – Daten über Ebenen teilen

provide · inject · Symbol · reactive
// Elternkomponente import { provide, ref } from 'vue'; provide('user', { name: 'Anna' }); // Kindkomponente import { inject } from 'vue'; const user = inject('user');

Provide / Inject ist eine Alternative zu Props für die Weitergabe von Daten über mehrere Komponentenebenen hinweg – ohne Prop Drilling.

Beispiele
// App.vue (Eltern)
<script setup>
import { provide, ref, readonly } from 'vue';
import Child from './Child.vue';
// Reaktive Daten bereitstellen
const theme = ref('dark');
const user = ref({ name: 'Anna', role: 'admin' });
// Provide mit Symbol (eindeutiger Schlüssel)
export const themeKey = Symbol('theme');
export const userKey = Symbol('user');
provide(themeKey, theme);
provide(userKey, readonly(user)); // Nur lesbar
provide('updateUser', (data) => {
user.value = { ...user.value, ...data };
});
</script>
<template>
<Child />
</template>
// Child.vue (tief verschachtelt)
<script setup>
import { inject } from 'vue';
import { themeKey, userKey } from './App.vue';
// Mit Standardwert (falls nicht vorhanden)
const theme = inject(themeKey, 'light');
const user = inject(userKey);
const updateUser = inject('updateUser');
function changeName() {
updateUser({ name: 'Max' });
}
</script>
<template>
<p>Thema: {{ theme }}</p>
<p>Benutzer: {{ user.name }} ({{ user.role }})</p>
<button @click="changeName">Name ändern</button>
</template>
Tipp: Verwenden Sie Symbol als Schlüssel für Provide/Inject, um Kollisionen zu vermeiden. Nutzen Sie readonly, um ungewollte Mutationen zu verhindern. Provide/Inject ist ideal für Theme, Sprache, Authentifizierungsstatus oder Datenbankverbindungen.

Vue.js Komponentenkonzepte im Überblick

Props Daten von Eltern zu Kind
Typisierung, Validierung
Events Kommunikation nach oben
$emit, v-model
Slots Flexible Inhalte
Benannte, Scoped
Composables Logik wiederverwenden
useFetch, useCounter
Dynamic Komponenten austauschen
<component :is>
Provide/Inject Daten über Ebenen
Theme, User, Config

Quick Summary

defineProps
Props typisieren
defineEmits
Events definieren
<slot>
Slots
useX
Composables
<component>
Dynamische Komponenten
provide
Provide/Inject
defineProps({ name: String }) · $emit('update', value) · v-slot="{ item }" · provide('key', value)