Zum Hauptinhalt springen

[Easy] Vue3 Neue Features

1. What are the new features in Vue 3?

Welche neuen Features hat Vue 3?

Vue 3 hat viele neue Features und Verbesserungen eingeführt, darunter:

Wichtigste neue Features

  1. Composition API: Neue Schreibweise für Komponenten
  2. Teleport: Komponenten an andere DOM-Positionen rendern
  3. Fragment: Komponenten können mehrere Wurzelknoten haben
  4. Suspense: Behandlung des Ladens asynchroner Komponenten
  5. Mehrere v-model: Unterstützung mehrerer v-model
  6. Bessere TypeScript-Unterstützung
  7. Performance-Optimierung: Kleinere Bundle-Größe, schnellere Rendergeschwindigkeit

2. Teleport

Was ist Teleport?

Definition: Teleport erlaubt es uns, den Inhalt einer Komponente an einer anderen Stelle im DOM-Baum zu rendern, ohne die logische Struktur der Komponente zu ändern.

Anwendungsszenarien

Gängige Szenarien: Modal, Tooltip, Notification und andere Komponenten, die im body gerendert werden müssen

Klicken Sie hier, um das Teleport-Beispiel zu erweitern
<template>
<div>
<button @click="showModal = true">Modal öffnen</button>

<!-- Teleport verwenden, um Modal im body zu rendern -->
<Teleport to="body">
<div v-if="showModal" class="modal">
<div class="modal-content">
<h2>Modal-Titel</h2>
<p>Modal-Inhalt</p>
<button @click="showModal = false">Schließen</button>
</div>
</div>
</Teleport>
</div>
</template>

<script setup>
import { ref } from 'vue';

const showModal = ref(false);
</script>

Vorteile

  1. Löst z-index-Probleme: Modal wird im body gerendert, unabhängig von Elternkomponenten-Stilen
  2. Behält logische Struktur bei: Komponentenlogik bleibt am ursprünglichen Ort, nur die DOM-Position ist anders
  3. Bessere Wartbarkeit: Modal-bezogener Code ist in der Komponente zentralisiert

3. Fragment (Mehrere Wurzelknoten)

Was ist Fragment?

Definition: Vue 3 erlaubt Komponenten mit mehreren Wurzelknoten, ohne sie in ein einzelnes Element einwickeln zu müssen. Dies ist ein implizites Fragment, es wird keine <Fragment>-Tag wie in React benötigt.

Vue 2 vs Vue 3

Vue 2: Einzelner Wurzelknoten erforderlich

<!-- Vue 2: Muss in einzelnes Element eingewickelt werden -->
<template>
<div>
<h1>Titel</h1>
<p>Inhalt</p>
</div>
</template>

Vue 3: Mehrere Wurzelknoten möglich

<!-- Vue 3: Mehrere Wurzelknoten möglich -->
<template>
<h1>Titel</h1>
<p>Inhalt</p>
</template>

Warum brauchen wir Fragment?

In Vue 2 mussten Komponenten einen einzelnen Wurzelknoten haben, was Entwickler oft zwang, zusätzliche Wrapper-Elemente (wie <div>) hinzuzufügen, die:

  1. Semantisches HTML brechen: Bedeutungslose Wrapper-Elemente hinzufügen
  2. DOM-Ebenen erhöhen: Stilselektoren und Performance beeinflussen
  3. Stilkontrolle erschweren: Stile des zusätzlichen Wrapper-Elements müssen behandelt werden

Anwendungsszenarien

Szenario 1: Semantische HTML-Struktur

<template>
<!-- Kein zusätzliches Wrapper-Element nötig -->
<header>
<h1>Seitentitel</h1>
</header>
<main>
<p>Hauptinhalt</p>
</main>
<footer>
<p>Fußzeile</p>
</footer>
</template>

Szenario 2: Listenelement-Komponente

<!-- ListItem.vue -->
<template>
<li class="item-title">{{ title }}</li>
<li class="item-description">{{ description }}</li>
</template>

<script setup>
defineProps({
title: String,
description: String,
});
</script>

Szenario 3: Bedingte Darstellung mehrerer Elemente

<template>
<div v-if="showHeader" class="header">Titel</div>
<div v-if="showContent" class="content">Inhalt</div>
<div v-if="showFooter" class="footer">Fußzeile</div>
</template>

Attributvererbung (Attribute Inheritance)

Bei Komponenten mit mehreren Wurzelknoten ändert sich das Verhalten der Attributvererbung.

Einzelner Wurzelknoten: Attribute werden automatisch an das Wurzelelement vererbt

<!-- Elternkomponente -->
<MyComponent class="custom-class" id="my-id" />

<!-- Kindkomponente (einzelner Wurzelknoten) -->
<template>
<div>Inhalt</div>
</template>

<!-- Render-Ergebnis -->
<div class="custom-class" id="my-id">Inhalt</div>

Mehrere Wurzelknoten: Attribute werden nicht automatisch vererbt, manuelle Zuweisung erforderlich

<!-- Elternkomponente -->
<MyComponent class="custom-class" id="my-id" />

<!-- Kindkomponente (mehrere Wurzelknoten) -->
<template>
<div>Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>
</template>

<!-- Render-Ergebnis: Attribute werden nicht automatisch vererbt -->
<div>Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>

Lösung: $attrs verwenden, um Attribute manuell zu binden

<!-- Kindkomponente -->
<template>
<div v-bind="$attrs">Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>
</template>

<!-- Render-Ergebnis -->
<div class="custom-class" id="my-id">Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>

inheritAttrs: false zur Steuerung des Vererbungsverhaltens:

<script setup>
defineOptions({
inheritAttrs: false, // Automatische Vererbung deaktivieren
});
</script>

<template>
<div v-bind="$attrs">Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>
</template>

Fragment vs React Fragment

EigenschaftVue 3 FragmentReact Fragment
SyntaxImplizit (keine Tags)Explizit (<Fragment> oder <>)
Key-AttributNicht erforderlichBei Bedarf <Fragment key={...}>
AttributvererbungManuelle BehandlungKeine Attributunterstützung

Vue 3:

<!-- Vue 3: Implizites Fragment -->
<template>
<h1>Titel</h1>
<p>Inhalt</p>
</template>

React:

// React: Explizites Fragment
function Component() {
return (
<>
<h1>Titel</h1>
<p>Inhalt</p>
</>
);
}

Hinweise

  1. Attributvererbung: Bei mehreren Wurzelknoten werden Attribute nicht automatisch vererbt, $attrs muss manuell verwendet werden
  2. Style-Scoping: Bei mehreren Wurzelknoten werden scoped-Stile auf alle Wurzelknoten angewendet
  3. Logisches Wrapping: Wenn logisch ein Wrapper benötigt wird, sollte weiterhin ein einzelner Wurzelknoten verwendet werden
<!-- ✅ Gute Praxis: Logisch ein Wrapper nötig -->
<template>
<div class="card">
<h2>Titel</h2>
<p>Inhalt</p>
</div>
</template>

<!-- ⚠️ Vermeiden: Mehrere Wurzelknoten ohne Notwendigkeit -->
<template>
<h2>Titel</h2>
<p>Inhalt</p>
<!-- Wenn diese Elemente logisch zusammengehören, sollten sie eingewickelt werden -->
</template>

4. Suspense

Was ist Suspense?

Definition: Suspense ist eine eingebaute Komponente zum Behandeln des Ladezustands asynchroner Komponenten.

Grundlegende Verwendung

<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Laden...</div>
</template>
</Suspense>
</template>

<script setup>
import { defineAsyncComponent } from 'vue';

const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
);
</script>

Anwendungsszenarien

  1. Laden asynchroner Komponenten

    <Suspense>
    <AsyncUserProfile :userId="userId" />
    <template #fallback>
    <UserProfileSkeleton />
    </template>
    </Suspense>
  2. Asynchrones Laden von Daten

    <script setup>
    const data = await fetchData(); // await im setup verwenden
    </script>

5. Multiple v-model

Mehrere v-model

Definition: Vue 3 erlaubt Komponenten die Verwendung mehrerer v-model, wobei jedes v-model einem anderen Prop entspricht.

Vue 2 vs Vue 3

Vue 2: Nur ein v-model

<!-- Vue 2: Nur ein v-model -->
<CustomInput v-model="value" />

Vue 3: Mehrere v-model möglich

<!-- Vue 3: Mehrere v-model möglich -->
<CustomForm
v-model:username="username"
v-model:email="email"
v-model:password="password"
/>

Implementierungsbeispiel

<!-- CustomForm.vue -->
<template>
<div>
<input
:value="username"
@input="$emit('update:username', $event.target.value)"
/>
<input :value="email" @input="$emit('update:email', $event.target.value)" />
<input
:value="password"
@input="$emit('update:password', $event.target.value)"
/>
</div>
</template>

<script setup>
defineProps(['username', 'email', 'password']);
defineEmits(['update:username', 'update:email', 'update:password']);
</script>

6. Common Interview Questions

Häufige Interviewfragen

Frage 1: Anwendungsszenarien von Teleport

Erklären Sie, wann Teleport verwendet werden sollte.

Klicken Sie hier, um die Antwort zu sehen

Szenarien für Teleport:

  1. Modal-Dialog

    <Teleport to="body">
    <Modal v-if="showModal" />
    </Teleport>
    • Löst z-index-Probleme
    • Unabhängig von Elternkomponenten-Stilen
  2. Tooltip

    <Teleport to="body">
    <Tooltip v-if="showTooltip" />
    </Teleport>
    • Vermeidet Verstecken durch overflow der Elternkomponente
  3. Notification

    <Teleport to="#notifications">
    <Notification v-for="msg in messages" :key="msg.id" />
    </Teleport>
    • Einheitliche Verwaltung der Benachrichtigungsposition

Kein Teleport nötig bei:

  • Allgemeinem Inhalt
  • Komponenten ohne besondere DOM-Positionsanforderungen

Frage 2: Vorteile von Fragment

Erklären Sie die Vorteile von mehreren Wurzelknoten in Vue 3.

Klicken Sie hier, um die Antwort zu sehen

Vorteile:

  1. Reduziert unnötige DOM-Elemente

    <!-- Vue 2: Zusätzliches div nötig -->
    <template>
    <div>
    <header>...</header>
    <main>...</main>
    </div>
    </template>

    <!-- Vue 3: Kein zusätzliches Element nötig -->
    <template>
    <header>...</header>
    <main>...</main>
    </template>
  2. Besseres semantisches HTML

    • Keine bedeutungslosen Wrapper-Elemente wegen Vue-Einschränkungen
    • Behält die Semantik der HTML-Struktur bei
  3. Flexiblere Stilkontrolle

    • Keine Behandlung von Wrapper-Element-Stilen nötig
    • Reduziert CSS-Selektor-Komplexität
  4. Weniger DOM-Ebenen

    • Flacherer DOM-Baum, bessere Performance
    • Reduziert Browser-Rendering-Kosten
  5. Bessere Wartbarkeit

    • Saubererer Code ohne zusätzliche Wrapper-Elemente
    • Klarere Komponentenstruktur

Frage 3: Fragment-Attributvererbungsproblem

Erklären Sie das Verhalten der Attributvererbung bei Komponenten mit mehreren Wurzelknoten. Wie löst man das?

Klicken Sie hier, um die Antwort zu sehen

Problem:

Bei Komponenten mit mehreren Wurzelknoten werden von der Elternkomponente übergebene Attribute (wie class, id usw.) nicht automatisch an einen Wurzelknoten vererbt.

Beispiel:

<!-- Elternkomponente -->
<MyComponent class="custom-class" id="my-id" />

<!-- Kindkomponente (mehrere Wurzelknoten) -->
<template>
<div>Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>
</template>

<!-- Render-Ergebnis: Attribute nicht automatisch vererbt -->
<div>Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>

Lösungen:

  1. $attrs verwenden, um Attribute manuell zu binden
<!-- Kindkomponente -->
<template>
<div v-bind="$attrs">Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>
</template>

<!-- Render-Ergebnis -->
<div class="custom-class" id="my-id">Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>
  1. inheritAttrs: false zur Steuerung des Vererbungsverhaltens
<script setup>
defineOptions({
inheritAttrs: false, // Automatische Vererbung deaktivieren
});
</script>

<template>
<div v-bind="$attrs">Erster Wurzelknoten</div>
<div>Zweiter Wurzelknoten</div>
</template>
  1. Selektives Binden bestimmter Attribute
<template>
<div :class="$attrs.class">Erster Wurzelknoten</div>
<div :id="$attrs.id">Zweiter Wurzelknoten</div>
</template>

Wichtige Punkte:

  • Einzelner Wurzelknoten: Attribute werden automatisch vererbt
  • Mehrere Wurzelknoten: Attribute werden nicht automatisch vererbt, manuelle Behandlung nötig
  • Mit $attrs kann auf alle nicht in props definierten Attribute zugegriffen werden

Frage 4: Fragment vs React Fragment

Vergleichen Sie Vue 3 Fragment und React Fragment.

Klicken Sie hier, um die Antwort zu sehen

Hauptunterschiede:

EigenschaftVue 3 FragmentReact Fragment
SyntaxImplizit (keine Tags)Explizit (<Fragment> oder <>)
Key-AttributNicht erforderlichBei Bedarf <Fragment key={...}>
AttributvererbungManuelle Behandlung ($attrs)Keine Attributunterstützung

Vue 3:

<!-- Vue 3: Implizites Fragment, direkt mehrere Wurzelknoten -->
<template>
<h1>Titel</h1>
<p>Inhalt</p>
</template>

React:

// React: Explizites Fragment, Tags erforderlich
function Component() {
return (
<>
<h1>Titel</h1>
<p>Inhalt</p>
</>
);
}

// Oder mit Fragment
import { Fragment } from 'react';
function Component() {
return (
<Fragment>
<h1>Titel</h1>
<p>Inhalt</p>
</Fragment>
);
}

Vorteilsvergleich:

  • Vue 3: Kompaktere Syntax, keine zusätzlichen Tags
  • React: Expliziter, Key-Attribut möglich

Frage 5: Verwendung von Suspense

Implementieren Sie ein Beispiel mit Suspense zum Laden einer asynchronen Komponente.

Klicken Sie hier, um die Antwort zu sehen
<template>
<Suspense>
<template #default>
<AsyncUserProfile :userId="userId" />
</template>
<template #fallback>
<div class="loading">
<Spinner />
<p>Benutzerdaten werden geladen...</p>
</div>
</template>
</Suspense>
</template>

<script setup>
import { ref } from 'vue';
import { defineAsyncComponent } from 'vue';
import Spinner from './Spinner.vue';

const userId = ref(1);

// Asynchrone Komponente definieren
const AsyncUserProfile = defineAsyncComponent(() =>
import('./UserProfile.vue')
);
</script>

Fortgeschrittene Verwendung: Fehlerbehandlung

<template>
<Suspense @resolve="onResolve" @reject="onReject">
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Laden...</div>
</template>
</Suspense>
</template>

<script setup>
const onResolve = () => {
console.log('Komponente erfolgreich geladen');
};

const onReject = (error) => {
console.error('Komponente konnte nicht geladen werden:', error);
};
</script>

7. Best Practices

Beste Praktiken

Empfohlene Vorgehensweisen

<!-- 1. Modal mit Teleport -->
<Teleport to="body">
<Modal v-if="showModal" />
</Teleport>

<!-- 2. Mehrere Wurzelknoten semantisch halten -->
<template>
<header>...</header>
<main>...</main>
<footer>...</footer>
</template>

<!-- 3. Asynchrone Komponenten mit Suspense -->
<Suspense>
<AsyncComponent />
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>

<!-- 4. Mehrere v-model mit eindeutigen Namen -->
<CustomForm v-model:username="username" v-model:email="email" />

Zu vermeidende Praktiken

<!-- 1. Teleport nicht übermäßig verwenden -->
<Teleport to="body">
<div>Allgemeiner Inhalt</div> <!-- ❌ Nicht nötig -->
</Teleport>

<!-- 2. Struktur nicht für mehrere Wurzelknoten aufbrechen -->
<template>
<h1>Titel</h1>
<p>Inhalt</p>
<!-- ⚠️ Wenn logisch ein Wrapper nötig ist, einzelnen Wurzelknoten verwenden -->
</template>

<!-- 3. Fehlerbehandlung bei Suspense nicht ignorieren -->
<Suspense>
<AsyncComponent />
<!-- ⚠️ Ladefehler sollten behandelt werden -->
</Suspense>

8. Interview Summary

Interview-Zusammenfassung

Schnelle Merkhilfe

Hauptneuerungen von Vue 3:

  • Composition API: Neue Schreibweise für Komponenten
  • Teleport: Komponenten an andere DOM-Positionen rendern
  • Fragment: Unterstützung mehrerer Wurzelknoten
  • Suspense: Behandlung des Ladens asynchroner Komponenten
  • Mehrere v-model: Unterstützung mehrerer v-model-Bindungen

Anwendungsszenarien:

  • Modal/Tooltip → Teleport
  • Semantisches HTML → Fragment
  • Asynchrone Komponenten → Suspense
  • Formularkomponenten → Mehrere v-model

Beispielantwort für Interviews

F: Welche sind die wichtigsten neuen Features von Vue 3?

"Vue 3 hat viele neue Features eingeführt, darunter: 1) Composition API, bietet eine neue Schreibweise mit besserer Logikorganisation und Wiederverwendbarkeit; 2) Teleport, erlaubt das Rendern von Komponenteninhalten an anderen DOM-Baum-Positionen, häufig verwendet für Modal, Tooltip usw.; 3) Fragment, Komponenten können mehrere Wurzelknoten haben ohne zusätzliche Wrapper-Elemente; 4) Suspense, behandelt den Ladezustand asynchroner Komponenten; 5) Mehrere v-model, unterstützt mehrere v-model-Bindungen pro Komponente; 6) Bessere TypeScript-Unterstützung und Performance-Optimierung. Diese Features machen Vue 3 leistungsfähiger und flexibler bei gleichzeitiger Abwärtskompatibilität."

F: Was sind die Anwendungsszenarien von Teleport?

"Teleport wird hauptsächlich in Szenarien verwendet, in denen Komponenten an anderen DOM-Baum-Positionen gerendert werden müssen. Gängige Szenarien sind: 1) Modal-Dialoge, die im body gerendert werden, um z-index-Probleme zu vermeiden; 2) Tooltips, die nicht durch overflow der Elternkomponente versteckt werden; 3) Benachrichtigungen mit einheitlicher Positionsverwaltung. Der Vorteil von Teleport ist, dass die logische Komponentenstruktur unverändert bleibt und nur die DOM-Renderposition geändert wird, was sowohl Stilprobleme löst als auch die Wartbarkeit des Codes beibehält."

Reference