Kapitel 4. Wechselwirkungen zwischen Komponenten

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

In Kapitel 3 haben wir uns eingehend mit der Komposition einer Komponente mit Lifecycle Hooks, berechneten Eigenschaften, Watchern, Methoden und anderen Funktionen beschäftigt. Außerdem haben wir gelernt, wie mächtig Slots sind und wie man mit Props externe Daten von anderen Komponenten erhält.

Auf dieser Grundlage zeigt dir dieses Kapitel, wie du die Interaktionen zwischen den Komponenten mithilfe von benutzerdefinierten Ereignissen und Provide/Inject-Mustern aufbaust. Außerdem wird die Teleport-API vorgestellt, mit der du Elemente im DOM-Baum verschieben kannst, ohne dass ihre Reihenfolge innerhalb einer Vue-Komponente verändert wird.

Verschachtelte Komponenten und Datenfluss in Vue

Vue-Komponenten können andere Vue-Komponenten in sich selbst verschachteln. Diese Funktion ist praktisch, um den Code in einem komplexen UI-Projekt in kleinere, überschaubare und wiederverwendbare Teile zu gliedern. Wir nennen verschachtelte Elemente Kindkomponenten und die Komponente, die sie enthält, ihre Elternkomponente .

Der Datenfluss in einer Vue-Anwendung ist standardmäßig unidirektional, was bedeutet, dass die übergeordnete Komponente Daten an die untergeordnete Komponente weitergeben kann, aber nicht umgekehrt. Die Elternkomponente kann Daten an die Kindkomponente weitergeben, indem sie props verwendet (siehe "Erkunden der Options-API"), und die Kindkomponente kann Ereignisse an die Elternkomponente zurücksenden, indem sie benutzerdefinierte Ereignisse emits verwendet. Abbildung 4-1 veranschaulicht den Datenfluss zwischen den Komponenten .

A diagram shows the one-way data flow between components
Abbildung 4-1. Einseitiger Datenfluss in Vue-Komponenten

Übergabe von Funktionen als Requisiten

Im Gegensatz zu anderen Frameworks ist es in Vue nicht möglich, eine Funktion als Prop an die Child-Komponente zu übergeben. Stattdessen kannst du die Funktion als benutzerdefinierten Ereignis-Emitter binden (siehe "Kommunikation zwischen Komponenten mitbenutzerdefinierten Ereignissen") .

Verwendung von Requisiten zur Weitergabe von Daten an untergeordnete Komponenten

In Form eines Objekts oder Arrays enthält das Feld props einer Vue-Komponente alle verfügbaren Dateneigenschaften, die die Komponente von ihrem Elternteil erhalten kann. Jede Eigenschaft von props ist eine Eigenschaft der Zielkomponente. Um Daten von der übergeordneten Komponente zu empfangen, musst du das Feld props im Optionsobjekt der Komponente deklarieren, wie in Beispiel 4-1 gezeigt.

Beispiel 4-1. Definieren von Requisiten in einer Komponente
export default {
  name: 'ChildComponent',
  props: {
    name: String
  }
}

In Beispiel 4-1 akzeptiert die Komponente ChildComponent einen name Prop vom Typ String. Die übergeordnete Komponente kann dann Daten an die untergeordnete Komponente weitergeben, indem sie diese name Prop benutzt, wie in Beispiel 4-2 gezeigt.

Beispiel 4-2. Übergabe statischer Daten als Requisiten an eine untergeordnete Komponente
<template>
  <ChildComponent name="Red Sweater" />
</template>
<script lang="ts">
import ChildComponent from './ChildComponent.vue'
export default {
  name: 'ParentComponent',
  components: {
    ChildComponent
  },
}
</script>

Die ChildComponent erhält im vorherigen Beispiel einen statischen "Red Sweater" als name Wert. Wenn du eine dynamische Datenvariable an name übergeben und binden möchtest, z. B. das erste Element in der Liste children, kannst du das Attribut v-bind verwenden, das mit : bezeichnet wird, wie in Beispiel 4-3 gezeigt.

Beispiel 4-3. Übergabe dynamischer Variablen als Requisiten an eine untergeordnete Komponente
<template>
  <ChildComponent :name="children[0]" />
</template>
<script lang="ts">
import ChildComponent from './ChildComponent.vue'
export default {
  //...
  data() {
    return {
      children: ['Red Sweater', 'Blue T-Shirt', 'Green Hat']
    }
  }
}
</script>

Die Ausgabe des vorherigen Codes ist die gleiche wie die Übergabe eines statischen Strings, Red Sweater, an die name prop.

Hinweis

Wenn die Requisite name nicht vom Typ String ist, musst du trotzdem dasv-bind Attribut (oder :) verwenden, um statische Daten an die untergeordnete Komponente zu übergeben, z. B. :name="true" für den Typ Boolean oder :name="["hello", "world"]" für den Typ Array.

Wenn sich in Beispiel 4-3 der Wert von children[0] ändert, aktualisiert Vue auch die name Prop in ChildComponent und die untergeordnete Komponente rendert ihren Inhalt bei Bedarf neu.

Wenn du mehr als eine Requisite in der untergeordneten Komponente hast, kannst du genauso vorgehen und die Daten an die entsprechende Requisite übergeben. Um zum Beispiel name und price eines Produkts an die Komponente ProductComp zu übergeben, kannst du Folgendes tun(Beispiel 4-4).

Beispiel 4-4. Übergabe mehrerer Requisiten an eine untergeordnete Komponente
/** components/ProductList.vue */
<template>
  <ProductComp :name="product.name" :price="product.price" />
</template>
<script lang="ts">
import ProductComp from './ProductComp.vue'
export default {
  name: 'ProductList',
  components: {
    ProductComp
  },
  data() {
    return {
      product: {
        name: 'Red Sweater',
        price: 19.99
      }
    }
  }
}
</script>

Und wir können die Komponente ProductComp wie in Beispiel 4-5 definieren.

Beispiel 4-5. Definieren mehrerer Requisiten in ProductComp
<template>
  <div>
    <p>Product: {{ name }}</p>
    <p>Price: {{ price }}</p>
  </div>
</template>
<script lang="ts">
export default {
  name: 'ProductComp',
  props: {
    name: String,
    price: Number
  }
}
</script>

Die Ausgabe sieht dann wie folgt aus:

Product: Red Sweater
Price: 19.99

Alternativ kannst du v-bind (nicht :) verwenden, um das gesamte Objekt user zu übergeben und seine Eigenschaften an die Requisiten der jeweiligen untergeordneten Komponente zu binden:

<template>
  <ProductComp v-bind="product" />
</template>

Beachte, dass nur die untergeordnete Komponente die entsprechenden deklarierten Requisiten erhält. Wenn du also in der übergeordneten Komponente ein weiteres Feld, product.description, hast, kann die untergeordnete Komponente nicht darauf zugreifen.

Hinweis

Eine andere Möglichkeit, die Komponente props zu deklarieren, ist die Verwendung eines Arrays von Strings, von denen jeder den Namen der akzeptierten Requisite darstellt, z. B. props: ["name", "price"]. Dieser Ansatz ist praktisch, wenn du schnell einen Prototyp für eine Komponente erstellen willst. Ich empfehle dir jedoch dringend, die Objektform von props zu verwenden und alle Requisiten mit Typen zu deklarieren, um die Lesbarkeit des Codes zu verbessern und Fehler zu vermeiden.

Wir haben gelernt, wie man Requisiten mit Typen deklariert, aber wie validieren wir die Daten, die an die Requisiten des Kindes übergeben werden, wenn sie benötigt werden? Wie können wir einen Fallback-Wert für eine Requisite festlegen, wenn kein Wert übergeben wird? Das werden wir als Nächstes herausfinden.

Deklaration von Prop-Typen mit Validierung und Standardwerten

In Beispiel 4-1 haben wir die Requisite name als Typ String deklariert. Vue gibt eine Warnung aus, wenn die übergeordnete Komponente während der Laufzeit einen Nicht-String-Wert an die Requisite name übergibt. Um jedoch in den Genuss der Typüberprüfung von Vue zu kommen, sollten wir die vollständige Deklarationssyntax verwenden:

{
  type: String | Number | Boolean | Array | Object | Date | Function | Symbol,
  default?: any,
  required?: boolean,
  validator?: (value: any) => boolean
}

In dem:

  • type ist der Typ der Requisite. Er kann eine Konstruktorfunktion (oder eine benutzerdefinierte Klasse) oder einer der eingebauten Typen sein.

  • default ist der Standardwert des Prop, wenn kein Wert übergeben wird. Für die Typen Object,Function, und Array muss der Standardwert eine Funktion sein, die den Anfangswert zurückgibt.

  • required ist ein boolescher Wert, der angibt, ob die Eigenschaft obligatorisch ist. Wenn required true ist, muss die übergeordnete Komponente einen Wert an die Requisite übergeben. Standardmäßig sind alle Requisiten optional.

  • validator ist eine Funktion, die den an prop übergebenen Wert validiert, hauptsächlich zur Fehlersuche bei der Entwicklung.

Wir können den name Prop genauer definieren und einen Standardwert angeben, wie in Beispiel 4-6 gezeigt.

Beispiel 4-6. Definieren von prop als String mit einem Standardwert
export default {
  name: 'ChildComponent',
  props: {
    name: {
      type: String,
      default: 'Child component'
    }
  }
}

Wenn die übergeordnete Komponente keinen Wert angibt, greift die untergeordnete Komponente auf den Standardwert "Child component" für die name prop zurück.

Wir können auch name als obligatorische Eigenschaft für die Kindkomponente festlegen und einen Validator für die empfangenen Daten hinzufügen, wie in Beispiel 4-7 gezeigt.

Beispiel 4-7. Name als erforderlich mit einem Prop-Validator definieren
export default {
  name: 'ChildComponent',
  props: {
    name: {
      type: String,
      required: true,
      validator: value => value !== "Child component"
    }
  }
}

Wenn in diesem Szenario die Elternkomponente keinen Wert an die name prop übergibt oder der angegebene Wert mit der Kindkomponente übereinstimmt, gibt Vue im Entwicklungsmodus eine Warnung aus(Abbildung 4-2) .

Screenshot of console warning for failed name prop validation
Abbildung 4-2. Konsolenwarnung in der Entwicklung bei fehlgeschlagener Stützenvalidierung
Hinweis

Für das Feld default ist der Typ Function eine Funktion, die den Anfangswert der Requisite zurückgibt. Du kannst ihn nicht verwenden, um Daten an die übergeordnete Komponente zurückzugeben oder um Datenänderungen auf der übergeordneten Ebene auszulösen.

Zusätzlich zu den eingebauten Typen und der Validierung, die Vue bietet, kannst du einen JavaScript Class oder einen Funktionskonstruktor und TypeScript kombinieren, um deinen eigenen Prop-Typ zu erstellen. Ich werde sie im nächsten Abschnitt behandeln.

Deklarieren von Requisiten mit benutzerdefinierter Typüberprüfung

Die Verwendung von primitiven Typen wie Array, String oder Object eignet sich für den grundlegenden Anwendungsfall. Wenn deine Anwendung jedoch wächst, können primitive Typen zu generisch sein, um den Typ deiner Komponente sicher zu halten. Nimm eine PizzaComponent mit dem folgenden Template-Code:

<template>
  <header>Title: {{ pizza.title }}</header>
  <div class="pizza--details-wrapper">
    <img :src="pizza.image" :alt="pizza.title" width="300" />
    <p>Description: {{ pizza.description }}</p>
    <div class="pizza--inventory">
      <div class="pizza--inventory-stock">Quantity: {{pizza.quantity}}</div>
      <div class="pizza--inventory-price">Price: {{pizza.price}}</div>
    </div>
  </div>
</template>

Diese Komponente akzeptiert einen obligatorischen pizza prop, der ein Object ist und einige Details über die pizza enthält:

export default {
  name: 'PizzaComponent',
  props: {
    pizza: {
      type: Object,
      required: true
    }
  }
}

Das ist ganz einfach. Indem wir jedoch pizza als Typ Object deklarieren, gehen wir davon aus, dass das Elternteil immer das passende Objekt mit den entsprechenden Feldern (title, image, description, quantity und price) übergibt, die für die Darstellung von pizza erforderlich sind.

Diese Annahme kann zu einem Problem führen. Da pizza Daten des Typs Object akzeptiert, kann jede Komponente, die PizzaComponent verwendet, beliebige Objektdaten an die Requisite pizza übergeben, ohne dass die eigentlichen Felder für eine pizza benötigt werden, wie in Beispiel 4-8.

Beispiel 4-8. Verwendung der Pizza-Komponente mit falschen Daten
<template>
  <div>
    <h2>Bad usage of Pizza component</h2>
    <pizza-component :pizza="{ name: 'Pinia', description: 'Hawaiian pizza' }" />
  </div>
</template>

Der vorangehende Code führt zu einer fehlerhaften Darstellung der Benutzeroberfläche von PizzaComponent, bei der nur description verfügbar ist und die restlichen Felder leer sind (mit einem fehlerhaften Bild), wie in Abbildung 4-3 gezeigt.

Screenshot of a pizza without title, price, quantity and image rendered
Abbildung 4-3. Defekte Benutzeroberfläche ohne Bildlink und fehlende Felder für eine Pizza

TypeScript kann die Datentypübereinstimmung auch hier nicht erkennen, da es die Typüberprüfung anhand des deklarierten Typs von pizza durchführt: dem generischen Object. Ein weiteres potenzielles Problem ist, dass die Übergabe von pizza im falschen Format der Nesteigenschaften die App zum Absturz bringen kann. Um solche Unfälle zu vermeiden, verwenden wir daher benutzerdefinierte Typendeklarationen.

Wir können die Klasse Pizza definieren und die Eigenschaft pizza vom Typ Pizza deklarieren, wie in Beispiel 4-9 gezeigt.

Beispiel 4-9. Einen benutzerdefinierten Typ Pizza deklarieren
class Pizza {
  title: string;
  description: string;
  image: string;
  quantity: number;
  price: number;

  constructor(
    title: string,
    description: string,
    image: string,
    quantity: number,
    price: number
  ) {
    this.title = title
    this.description = description
    this.image = image
    this.quantity = quantity
    this.price = price
  }
}

export default {
  name: 'PizzaComponent',
  props: {
    pizza: {
      type: Pizza, 1
      required: true
    }
  }
}
1

Deklariere den Typ der pizza Requisiten direkt als Pizza

Alternativ kannst du auch interface oder type von TypeScript verwenden, um deinen benutzerdefinierten Typ anstelle von Class zu definieren. In solchen Szenarien musst du jedoch den Typ PropType aus dem Paket vue mit der folgenden Syntax verwenden, um den deklarierten Typ auf die Zielprop abzubilden:

type: Object as PropType<Your-Custom-Type>

Schreiben wir stattdessen die Klasse Pizza als interface um(Beispiel 4-10).

Beispiel 4-10. Deklarieren eines benutzerdefinierten Pizza-Typs mit der TypeScript-Schnittstellen-API
import type { PropType } from 'vue'

interface Pizza {
  title: string;
  description: string;
  image: string;
  quantity: number;
  price: number;
}

export default {
  name: 'PizzaComponent',
  props: {
    pizza: {
      type: Object as PropType<Pizza>, 1
      required: true
    }
  }
}
1

Deklariere den Typ der pizza Requisiten als Pizza Schnittstelle mit PropType Hilfe.

Wenn du PizzaComponent mit dem falschen Datenformat verwendest, wird TypeScript den Fehler erkennen und entsprechend hervorheben.

Hinweis

Vue führt die Typüberprüfung während der Laufzeit durch, während TypeScript die Typüberprüfung während der Kompilierungszeit durchführt. Daher ist es eine gute Praxis, sowohl die Typprüfung von Vue als auch die Typprüfung von TypeScript zu verwenden, um sicherzustellen, dass dein Code fehlerfrei ist .

Requisiten mit defineProps() und withDefaults() deklarieren

Wie wir in "Setup" gelernt haben , bietet Vue ab Vue 3.x eine <script setup> Syntax für die Deklaration einer funktionalen Komponente ohne die klassische Options-API. Innerhalb dieses <script setup> Blocks kannst du defineProps() verwenden, um Props zu deklarieren, wie in Beispiel 4-11 gezeigt.

Beispiel 4-11. Requisitendeklaration mit defineProps() und <script setup>
<script setup>
import { defineProps } from 'vue'

const props = defineProps({
  name: {
    type: String,
    default: "Hello from the child component."
  }
})
</script>

Dank TypeScript können wir auch den akzeptierten Typ für defineProps() pro Komponente mit Typvalidierung zur Kompilierzeit deklarieren, wie in Beispiel 4-12 gezeigt.

Beispiel 4-12. Requisitendeklaration mit defineProps() und TypeScript type
<script setup >
import { defineProps } from 'vue'

type ChildProps = {
  name?: string
}

const props = defineProps<ChildProps>()
</script>

In diesem Fall müssen wir, um den Standardwert der Requisite message zu deklarieren, den Aufruf defineProps() mit withDefaults() umschließen, wie in Beispiel 4-13.

Beispiel 4-13. Requisitendeklaration mit defineProps() und withDefaults()
import { defineProps, withDefaults } from 'vue'

type ChildProps = {
  name?: string
}

const props = withDefaults(defineProps<ChildProps>(), {
  name: 'Hello from the child component.'
})

Verwendung von defineProps() mit TypeScript Type Checking

Bei der Verwendung von defineProps() können wir die Laufzeit- und die Kompilierzeit-Typüberprüfung nicht kombinieren. Ich empfehle die Verwendung von defineProps() für den Ansatz in Beispiel 4-11, um eine bessere Lesbarkeit und eine Kombination aus Vue- und TypeScript-Typenprüfung zu erreichen.

Wir haben gelernt, wie man Props für die Übergabe von Rohdaten in einer Vue-Komponente deklariert, mit Typüberprüfung und Validierung. Als Nächstes werden wir uns ansehen, wie man Funktionen als benutzerdefinierte Ereignisauslöser an eine untergeordnete Komponente weitergibt .

Kommunikation zwischen Komponenten mitbenutzerdefinierten Ereignissen

Vue behandelt Daten, die über Props an eine untergeordnete Komponente übergeben werden, als schreibgeschützte und rohe Daten. Der einseitige Datenfluss stellt sicher, dass die übergeordnete Komponente die einzige ist, die die Datenprops aktualisieren kann. Oft wollen wir eine bestimmte Datenreferenz aktualisieren und mit der übergeordneten Komponente synchronisieren. Dazu verwenden wir das Feld emits in den Optionen der Komponente, um benutzerdefinierte Ereignisse zu deklarieren.

Nimm zum Beispiel eine To-Do-Liste oder die Komponente ToDoList. Diese ToDoList verwendetToDoItem als untergeordnete Komponente, um eine Liste von Aufgaben mit dem Code in Beispiel 4-14 darzustellen.

Beispiel 4-14. ToDoList Komponente
<template>
  <ul style="list-style: none;">
    <li v-for="task in tasks" :key="task.id">
      <ToDoItem :task="task" />
    </li>
  </ul>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import ToDoItem from './ToDoItem.vue'
import type { Task } from './ToDoItem'

export default defineComponent({
  name: 'ToDoList',
  components: {
    ToDoItem
  },
  data() {
    return {
      tasks: [
        { id: 1, title: 'Learn Vue', completed: false },
        { id: 2, title: 'Learn TypeScript', completed: false },
        { id: 3, title: 'Learn Vite', completed: false },
      ] as Task[]
    }
  }
})
</script>

Und ToDoItem ist eine Komponente, die ein task Attribut erhält und ein input als Kontrollkästchen darstellt, mit dem der Nutzer die Aufgabe als erledigt oder nicht erledigt markieren kann. Dieses Element input erhält task.completed als Anfangswert für das Attribut checked. Sehen wir uns Beispiel 4-15 an.

Beispiel 4-15. ToDoItem Komponente
<template>
  <div>
    <input
      type="checkbox"
      :checked="task.completed"
    />
    <span>{{ task.title }}</span>
  </div>
</template>
<script lang="ts">
import { defineComponent, type PropType } from 'vue'

export interface Task {
  id: number;
  title: string;
  completed: boolean;
}

export default defineComponent({
  name: 'ToDoItem',
  props: {
    task: {
      type: Object as PropType<Task>,
      required: true,
    }
  },
})
</script>

Wenn ein Benutzer dieses input Kästchen anklickt, wollen wir ein Ereignis namens task-completed-toggle auslösen, um die übergeordnete Komponente über den task.completed Wert der jeweiligen Aufgabe zu informieren. Dazu deklarieren wir das Ereignis zunächst im Feld emits der Optionen der Komponente(Beispiel 4-16).

Beispiel 4-16. ToDoItem Komponente mit Emits
/** ToDoItem.vue */
export default defineComponent({
  //...
  emits: ['task-completed-toggle']
})

Dann erstellen wir eine neue Methode onTaskCompleted, um das Ereignis task-completed-toggle mit dem neuen Wert von task.completed aus dem Kontrollkästchen und task.id als Nutzlast des Ereignisses zu senden(Beispiel 4-17).

Beispiel 4-17. ToDoItem Komponente mit einer Methode zur Ausgabe des Ereignisses task-completed-toggle
/** ToDoItem.vue */
export default defineComponent({
  //...
  methods: {
    onTaskCompleted(event: Event) {
      this.$emit("task-completed-toggle", {
        ...this.task,
        completed: (event.target as HTMLInputElement)?.checked,
      });
    },
  }
})
Hinweis

Wir verwenden defineComponent, um die Optionen der Komponente zu umschließen und eine TypeScript-freundliche Komponente zu erstellen. Die Verwendung von defineComponent ist für einfache Komponenten nicht erforderlich, aber du musst sie verwenden, um auf andere Dateneigenschaften von this in den Methoden, Hooks oder berechneten Eigenschaften der Komponenten zuzugreifen. Andernfalls wird TypeScript einen Fehler auslösen.

Dann binden wir die Methode onTaskCompleted an das Ereignis change des Elements input, wie in Beispiel 4-18 gezeigt.

Beispiel 4-18. Die aktualisierte Vorlage der KomponenteToDoItem
<div>
  <input
    type="checkbox"
    :checked="task.completed"
    @change="onTaskCompleted"
  />
  <span>{{ task.title }}</span>
</div>

Jetzt können wir in der übergeordneten Komponente <ToDoList> von ToDoItem das Ereignis task-completed-toggle mit der Notation @ an eine Methode binden, und zwar mit der Vorlage in Beispiel 4-19.

Beispiel 4-19. Die aktualisierte Vorlage der KomponenteToDoList
<template>
  <ul style="list-style: none;">
    <li v-for="task in tasks" :key="task.id">
      <ToDoItem
        :task="task"
        @task-completed-toggle="onTaskCompleted"
      />
    </li>
  </ul>
</template>

Die Methode onTaskCompleted in der übergeordneten Komponente <ToDoList> erhält die Nutzlast des Ereignisses task-completed-toggle und aktualisiert den Wert task.completed der spezifischen Aufgabe im Array tasks, wie in Beispiel 4-20.

Beispiel 4-20. Das Skript der KomponenteToDoList mit einer Methode zur Behandlung des Ereignisses task-completed-toggle
//...

export default {
  //...
  methods: {
    onTaskCompleted(payload: { id: number; completed: boolean }) {
      const index = this.tasks.findIndex(t => t.id === payload.id)

      if (index < 0) return

      this.tasks[index].completed = payload.completed
    }
  }
}

Diese Codeblöcke werden die in Abbildung 4-4 gezeigte Seite darstellen.

Screenshot of a to-do list with three tasks, each with a checkbox and task's title
Abbildung 4-4. ToDoList Komponente mit drei Elementen

Vue aktualisiert die zugehörigen Daten in ToDoList und rendert entsprechend die entsprechende ToDoItem Komponenteninstanz. Du kannst das Kontrollkästchen aktivieren, um ein To-Do als erledigt zu markieren. Abbildung 4-5 zeigt, dass wir das Ereignis der Komponente mithilfe der VueDevtools erkennen können.

A screenshot of the Vue Devtools showing the event emitted by the +ToDoItem+ component
Abbildung 4-5. Markieren einer Aufgabe als erledigt und Debuggen des Ereignisses, das mit denVue Devtools ausgelöst wurde

Benutzerdefinierte Ereignisse mit defineEmits() definieren

Ähnlich wie bei der "Deklaration von Requisiten mit defineProps() und withDefaults()" kannst du innerhalb eines <script setup> Codeblocks defineEmits() verwenden, um eigene Ereignisse zu definieren. Die Funktion defineEmits() akzeptiert denselben Eingabeparametertyp wie emits :

const emits = defineEmits(['component-event'])

Sie gibt dann eine Funktionsinstanz zurück, die wir verwenden können, um ein bestimmtes Ereignis von der Komponente aufzurufen:

emits('component-event', [...arguments])

So können wir den Skriptabschnitt von ToDoItem wie in Beispiel 4-21 schreiben.

Beispiel 4-21. ToDoItem Komponente mit dem benutzerdefinierten Ereignis mit defineEmits()
<script lang="ts" setup>
//...
const props = defineProps({
  task: {
    type: Object as PropType<Task>,
    required: true,
  }
});

const emits = defineEmits(['task-completed-toggle'])

const onTaskCompleted = (event: Event) => {
  emits("task-completed-toggle", {
    id: props.task.id,
    completed: (event.target as HTMLInputElement)?.checked,
  });
}
</script>

Beachte, dass wir hier nicht defineComponent verwenden müssen, da es keine this Instanz innerhalb des <script setup> Codeblocks gibt.

Für eine bessere Typüberprüfung kannst du für das Ereignis task-completed-toggle eine Nur-Typ-Deklaration anstelle eines einzelnen Strings verwenden. Verbessern wir die emits Deklaration in Beispiel 4-21 und verwenden den Typ EmitEvents wie in Beispiel 4-22 gezeigt.

Beispiel 4-22. Benutzerdefiniertes Ereignis mit defineEmits() und Nur-Typ-Deklaration
// Declare the emit type
type EmitEvents = {
  (e: 'task-completed-toggle', task: Task): void;
}

const emits = defineEmits<EmitEvents>()

Auf diese Weise kannst du sicherstellen, dass du die richtige Methode an das deklarierte Ereignis bindest. Wie beim Ereignis task-complete-toggle sollte jede Ereignisdeklaration demselben Muster folgen:

(e: 'component-event', [...arguments]): void

In der vorherigen Syntax ist e der Name des Ereignisses, und arguments sind alle Eingaben, die an den Ereignisauslöser übergeben werden. Im Fall des Ereignisses task-completed-toggle ist das Argument des Emitters task vom Typ Task.

emits ist eine leistungsstarke Funktion, mit der du die Zwei-Wege-Kommunikation zwischen einer Eltern- und einer Kindkomponente ermöglichen kannst, ohne den Datenflussmechanismus von Vue zu unterbrechen. props und emits sind jedoch nur von Vorteil, wenn du eine direkte Datenkommunikation wünschst.

Du musst einen anderen Ansatz verwenden, um Daten von einer Komponente an ihr Enkelkind oder ihren Nachkommen zu übergeben. Im nächsten Abschnitt werden wir sehen, wie du die APIs provide und inject verwendest, um Daten von einer übergeordneten Komponente an ihre untergeordnete oder Enkelkomponente zu übergeben.

Kommunikation zwischen Komponenten mitprovide/inject-Muster

Um die Datenkommunikation zwischen einer Vorgängerkomponente und ihren Nachfolgern herzustellen, ist die provide/inject API eine sinnvolle Option. Das Feld provide übergibt Daten von der Vorgängerkomponente, während inject sicherstellt, dass Vue die bereitgestellten Daten in jeden Zielnachfolger injiziert.

Daten weitergeben mit provide

Das Optionsfeld der Komponente provide akzeptiert zwei Formate: ein Datenobjekt oder eineFunktion.

provide kann ein Objekt sein, das zu injizierende Daten enthält, wobei jede Eigenschaft einen Datentyp (Schlüssel, Wert) darstellt. Im folgenden Beispiel liefert ProductList einen Datenwert, selectedIds, mit dem Wert [1] an alle seine Nachkommen(Beispiel 4-23).

Beispiel 4-23. Übergabe von selectedIds mittels provide in der Komponente ProductList
export default {
  name: 'ProductList',
  //...
  provide: {
    selectedIds: [1]
  },
}

Ein weiterer Formattyp für provide ist eine Funktion, die ein Objekt zurückgibt, das die Daten enthält, die für die Nachkommenschaft injiziert werden können. Ein Vorteil dieses Formattyps ist, dass wir auf die Instanz this zugreifen und dynamische Daten oder eine Komponentenmethode auf die entsprechenden Felder des Rückgabeobjekts mappen können. Aus Beispiel 4-23 können wir das Feld provide in eine Funktion umschreiben, wie in Beispiel 4-24 gezeigt.

Beispiel 4-24. Übergabe von selectedIds mittels provide in der Komponente ProductList als Funktion
export default {
//...
  provide() {
    return {
      selectedIds: [1]
    }
  },
//...
}
</script>
Hinweis

Im Gegensatz zu props kannst du eine Funktion übergeben und sie über das Feld provide vom Zielnachfolger auslösen lassen. Auf diese Weise können Daten an die übergeordnete Komponente zurückgeschickt werden. Vue betrachtet diesen Ansatz jedoch als Anti-Pattern und du solltest ihn mit Bedacht einsetzen.

An diesem Punkt übergibt unser ProductList einige Datenwerte an seinen Nachkommen mitprovide. Als Nächstes müssen wir die bereitgestellten Werte injizieren, um innerhalb eines Nachfolgers zu operieren.

Injizieren zum Empfangen von Daten verwenden

Wie props kann auch das Feld inject ein Array von Strings akzeptieren, die jeweils für den angegebenen Datenschlüssel (inject: [selectedId]) oder ein Objekt darstellt.

Wenn du inject als Objektfeld verwendest, ist jede seiner Eigenschaften ein Objekt, wobei der Schlüssel den lokalen Datenschlüssel darstellt, der innerhalb der Komponente verwendet wird, und die folgendenEigenschaften:

{
  from?: string;
  default: any
}

Hier ist from optional, wenn der Eigenschaftsschlüssel derselbe ist wie der vom Vorgänger bereitgestellte Schlüssel. Nehmen wir zum Beispiel Beispiel Beispiel 4-23 mit selectedIds als Daten, die von ProductList an seine Nachkommen weitergegeben werden. Wir können ein ProductComp berechnen, das die bereitgestellten Daten selectedIds von ProductList erhält und es in currentumbenennenSelectedIds um es lokal zu verwenden, wie in Beispiel 4-25 gezeigt.

Beispiel 4-25. Injizieren von bereitgestellten Daten in ProductComp
<script lang='ts'>
export default {
  //...
  inject: {
    currentSelectedIds: {
      from: 'selectedIds',
      default: []
    },
  },
}
</script>

In diesem Code nimmt Vue den Wert von selectedIds und weist ihn einem lokalen Datenfeld, currentSelectedIds, zu oder verwendet den Standardwert [], wenn es keinen injizierten Wert gibt.

Wenn du im Abschnitt Komponenten auf der Registerkarte Vue in den Entwicklertools des Browsers ProductComp aus dem Komponentenbaum auswählst (linke Seite), kannst du die Anzeige der Umbenennung für die injizierten Daten debuggen (rechte Seite), wie in Abbildung 4-6 gezeigt.

A screenshot shows the Component tab of the Vue tab in the browser's Develop tools with information about a component's provided and injected data.
Abbildung 4-6. Debuggen der bereitgestellten und injizierten Daten mit den Vue Devtools
Hinweis

Die entsprechenden Hooks in der Composition API für provide/inject sind provide() und inject(), bzw. .

Jetzt wissen wir, wie wir provide und inject verwenden können, um Daten zwischen Komponenten effizient und ohne Requisiten zu übergeben. Sehen wir uns an, wie wir einen bestimmten Inhaltsbereich eines Elements an einer anderen Stelle im DOM mit der Komponente <Teleport> rendern können.

Teleport API

Aufgrund von Styling-Einschränkungen müssen wir oft eine Komponente implementieren, die Elemente enthält, die von Vue an einer anderen Stelle im DOM gerendert werden sollen, um den vollen visuellen Effekt zu erzielen. In solchen Fällen müssen wir diese Elemente in der Regel an die gewünschte Stelle "teleportieren", indem wir eine komplexe Lösung entwickeln, was sich negativ auf die Leistung auswirkt, Zeit kostet usw. Um diese "Teleport"-Herausforderung zu lösen, bietet Vue dieKomponente <Teleport> .

Die Komponente <Teleport> akzeptiert einen prop to, der den Zielcontainer angibt, entweder den Abfrage-Selektor eines Elements oder das gewünschte HTML-Element. Angenommen, wir haben eine House Komponente, die einen Ausschnitt des Himmels und der Wolken enthält, der von der Vue-Engine zu einem bestimmten #sky DOM-Element teleportiert werden muss, wie in Beispiel 4-26.

Beispiel 4-26. Hauskomponente mit Teleport
<template>
  <div>
    This is a house
  </div>
  <Teleport to="#sky">
    <div>Sky and clouds</div>
  </Teleport>
</template>

In unserem App.vue fügen wir ein section Element mit der Ziel-ID sky oberhalb der House Komponente ein, wie in Beispiel 4-27.

Beispiel 4-27. Template von App.vue mit House Komponente
<template>
  <section id="sky" />
  <section class="wrapper">
      <House />
  </section>
</template>

Abbildung 4-7 zeigt die Codeausgaben.

Screenshot displaying two texts in the reverse order
Abbildung 4-7. Tatsächliche Anzeigereihenfolge bei Verwendung der Komponente Teleport

Wenn du den DOM-Baum auf der Registerkarte "Elemente" in den Entwicklertools des Browsers inspizierst, erscheint "Himmel und Wolken" stattdessen als verschachtelt innerhalb von <section id="sky"> (Abbildung 4-8).

Screenshot displaying the DOM tree
Abbildung 4-8. Tatsächlicher DOM-Baum bei Verwendung der Komponente Teleport

Du kannst auch das Verschieben des Inhalts innerhalb einer <Teleport> Komponenteninstanz mit der booleschen Eigenschaft disabled vorübergehend deaktivieren. Diese Komponente ist praktisch, wenn du die DOM-Baumstruktur beibehalten willst und Vue bei Bedarf nur den gewünschten Inhalt an die Zielposition verschieben soll. Ein alltäglicher Anwendungsfall für Teleport ist ein Modal, das wir als Nächstes implementieren werden.

Beide Abschnitte unter einem Elternteil zusammenfassen

Die Zielkomponente für die Teleportation muss im DOM vorhanden sein, bevor <Teleport> eingebunden wird. Wenn du in Beispiel 4-27 beide Instanzen von section unter einem main Element einbindest, funktioniert die Komponente <Teleport> nicht wie erwartet. Siehe "Rendering-Problem mit Teleport" für weitere Details.

Ein Modal mit Teleport und dem <dialog>-Element implementieren

Ein Modal ist ein Dialogfenster, das oben auf dem Bildschirm erscheint und die Interaktion des Nutzers mit der Hauptseite blockiert. Der Nutzer muss mit dem Modal interagieren, um es zu schließen, und kehrt dann zur Hauptseite zurück.

Ein Modal ist sehr praktisch, um wichtige Benachrichtigungen anzuzeigen, die die volle Aufmerksamkeit des Nutzers erfordern und nur einmal erscheinen sollten.

Lass uns ein einfaches Modal entwerfen. Ähnlich wie ein Dialog, sollte ein Modal die folgenden Elemente enthalten(Abbildung 4-9):

  • Ein Hintergrund, der den gesamten Bildschirm bedeckt, auf dem das Modal erscheint und die Interaktionen des Nutzers mit der aktuellen Seite blockiert.

  • Ein modales Fenster, das den Inhalt des Modals enthält, einschließlich eines header mit einem Titel und einer Schaltfläche zum Schließen, einem main Inhaltsbereich und einem footer Bereich mit einer Standard-Schließschaltfläche. Diese drei Abschnitte sollten mit den Slots angepasst werden können.

Screenshot displaying the design of a basic modal.
Abbildung 4-9. Entwurf eines Basismodals

Basierend auf dem vorangegangenen Entwurf implementieren wir eine Modal Komponentenvorlage mit dem <dialog> HTML-Element in Beispiel 4-28.

Beispiel 4-28. Modal Komponente
<template>
  <dialog :open="open">
    <header>
      <slot name="m-header"> 1
        <h2>{{ title }}</h2>
        <button>X</button>
      </slot>
    </header>
    <main>
      <slot name="m-main" /> 2
    </main>
    <footer>
      <slot name="m-footer"> 3
        <button>Close</button>
      </slot>
    </footer>
  </dialog>
</template>

Im vorangegangenen Code verwenden wir drei Slot-Abschnitte, damit der Nutzer sie anpassen kann:

1

Die Kopfzeile des Modals (m-header)

2

Der Hauptinhalt (m-main)

3

Die Fußzeile des Modals (m-footer)

Außerdem binden wir das open Attribut des <dialog> Elements an eine lokale Datenreferenz open zur Steuerung der Sichtbarkeit des Modals (sichtbar/unsichtbar). Darüber hinaus wird der title prop als Standardtitel des Modals gerendert. Nun wollen wir die Optionen der Komponente Modal implementieren, die zwei Requisiten erhalten: open und title, wie in Beispiel 4-29.

Beispiel 4-29. Hinzufügen von Requisiten zur Komponente Modal
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'Modal',
  props: {
    open: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      default: 'Dialog',
    },
  },
})
</script>

Wenn ein Nutzer auf die Schaltfläche zum Schließen des Modals oder auf die Schaltfläche "X" in der Kopfzeile klickt, sollte es sich selbst schließen. Da wir die Sichtbarkeit des Modals mit der Requisite open steuern, müssen wir ein Ereignis closeDialog mit dem neuen Wert von open von der Komponente Modal an das Elternteil senden. Wir deklarieren emits und eine close Methode, die das Zielereignis ausgibt, wie in Beispiel 4-30 .

Beispiel 4-30. Deklaration des Ereignisses closeDialog für Modal zum Aussenden
<script lang="ts">
/** Modal.vue */
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'Modal',
  //...
  emits: ["closeDialog"], 1
  methods: {
    close() { 2
      this.$emit("closeDialog", false);
    },
  },
})
</script>
1

emits mit einer Veranstaltung, closeDialog

2

close Methode, die das Ereignis closeDialog mit dem neuen Wert von open ausgibt, als false

Dann binden wir sie mit Hilfe der @ Notation an die entsprechenden Aktionselemente im <dialog> Element, wie in Beispiel 4-31 gezeigt.

Beispiel 4-31. Ereignis-Listener auf Klick-Ereignisse binden
<template>
  <dialog :open="open" >
    <header>
      <slot name="m-header" >
        <h2>{{ title }}</h2>
        <button @click="close" >X</button> 1
      </slot>
    </header>
    <main>
      <slot name="m-main" />
    </main>
    <footer>
      <slot name="m-footer" >
        <button @click="close" >Close</button> 2
      </slot>
    </footer>
  </dialog>
</template>
1

@click Ereignishandler für die Schaltfläche "X" in der Kopfzeile

2

@click Ereignishandler für die Standard-Schließschaltfläche in der Fußzeile

Als Nächstes müssen wir das Element dialog mit einer Komponente <Teleport> umhüllen, um es außerhalb des DOM-Baums der übergeordneten Komponente zu platzieren. Außerdem übergeben wir der Komponente den Prop to <Teleport> Komponente, um den Zielort festzulegen: ein HTML-Element mit der ID modal. Zum Schluss binden wir die Requisite disabled an den Wert open der Komponente, um sicherzustellen, dass Vue nur den Inhalt der modalen Komponente an die gewünschte Stelle verschiebt, wenn sie sichtbar ist(Beispiel 4-32).

Beispiel 4-32. Verwendung der Komponente <Teleport>
<template>
  <teleport 1
    to="#modal" 2
    :disabled="!open" 3
  >
    <dialog ref="dialog" :open="open" >
      <header>
      <slot name="m-header">
        <h2>{{ title }}</h2>
        <button @click="close" >X</button>
      </slot>
      </header>
      <main>
        <slot name="m-main" />
      </main>
      <footer>
        <slot name="m-footer">
          <button @click="close" >Close</button>
        </slot>
      </footer>
    </dialog>
  </teleport>
</template>
1

<Teleport> Komponente

2

to Prop mit dem Zielort mit id-Selektor modal

3

disabled Prop mit der Bedingung, dass der open Wert der Komponente falsch ist

Probieren wir nun unsere Modal Komponente in einer WithModalComponent aus, indem wir den folgenden Code aus Beispiel 4-33 in die WithModalComponent einfügen.

Beispiel 4-33. Verwendung der modalen Komponente in WithModalComponent
<template>
  <h2>With Modal component</h2>
  <button @click="openModal = true">Open modal</button>
  <Modal :open="openModal" title="Hello World" @closeDialog="toggleModal"/>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Modal from "./Modal.vue";

export default defineComponent({
  name: "WithModalComponent",
  components: {
    Modal,
  },
  data() {
    return {
      openModal: false,
    };
  },
  methods: {
    toggleModal(newValue: boolean) {
      this.openModal = newValue;
    },
  },
});
</script>

Zum Schluss fügst du ein Element <div> mit der ID modal zum Element body in der Datei index.html hinzu:

<body>
  <div id="app"></div>
  <div id="modal"></div> 1
  <script type="module" src="/src/main.ts"></script>
</body>
1

div Element mit id modal

Auf diese Weise rendert Vue den Inhalt der Komponente Modal auf diese div mit der ID modal, wenn der Prop open auf true (Abbildung 4-10) gesetzt wird.

Modal component rendered to the +div+ with id +modal+ when visible
Abbildung 4-10. Modale Komponente, die auf div mit der id modal gerendert wird, wenn sie sichtbar ist

Abbildung 4-11 zeigt, wie es auf dem Bildschirm aussieht:

Output of the +WithModalComponent+ when modal is visible
Abbildung 4-11. Ausgabe der WithModalComponent, wenn das Modal sichtbar ist

Und wenn die Requisite open false ist, ist die Requisite div mit der Id modal leer(Abbildung 4-12) und das Modal ist auf dem Bildschirm unsichtbar(Abbildung 4-13).

Modal component not rendered to the +div+ with id +modal+ when hidden
Abbildung 4-12. Modale Komponente wird nicht auf div mit der id modal gerendert, wenn sie ausgeblendet ist
Modal component not visible when hidden
Abbildung 4-13. Modale Komponente nicht sichtbar, wenn ausgeblendet

Jetzt hast du eine funktionierende modale Komponente. Allerdings sieht das Modal nicht ganz so gut aus, wie wir es uns gewünscht haben. Wenn das Modal sichtbar ist, sollte sich ein dunkler Overlay über den Hauptinhalt der Seite legen. Beheben wir dieses Problem mit CSS-Stylings für den ::backdrop -Selektor im <style> -Abschnitt des Modalelements:

<style scoped>
  dialog::backdrop {
    background-color: rgba(0, 0, 0, 0.5);
  }
</style>

Das Aussehen des Hintergrunds des Modals wird dadurch jedoch nicht verändert. Das liegt daran, dass der Browser die ::backdrop CSS-Selektorregeln nur dann auf das Dialogfeld anwendet, wenn wir das Dialogfeld mit der Methode dialog.showModal() öffnen, und nicht, wenn wir das Attribut open ändern. Um dieses Problem zu beheben, müssen wir die folgenden Änderungen in unserer Modal Komponente vornehmen:

  • Füge einen direkten Verweis auf das Element <dialog> hinzu, indem du dem Attribut ref den Wert "dialog" zuweist:

    <dialog :open="open" ref="dialog">
      <!--...-->
    </dialog>
  • Löse $refs.dialog.showModal() oder $refs.dialog.close() auf dem Element dialog aus, wenn sich die Requisite open mit watch ändert:

    watch: {
      open(newValue) {
        const element = this.$refs.dialog as HTMLDialogElement;
        if (newValue) {
          element.showModal();
        } else {
          element.close();
        }
      },
    },
  • Entferne die ursprüngliche Bindung für das Attribut open des Elements <dialog>:

    <dialog ref="dialog">
      <!--...-->
    </dialog>
  • Entferne die Verwendung des Attributs disabled in der Komponente <teleport>:

    <teleport to="#modal">
      <!--...-->
    </teleport>

Wenn du das Modal mit der eingebauten Methode showModal() öffnest, fügt der Browser ein ::backdrop Pseudo-Element zum eigentlichen <dialog> Element im DOM hinzu. Wenn du den Inhalt des Elements dynamisch an die Zielposition verschiebst, wird diese Funktion deaktiviert und das Modal bleibt ohne den gewünschten Hintergrund.

Außerdem positionieren wir das Modal neu in der Mitte der Seite und über anderen Elementen, indem wir die folgenden CSS-Regeln zum dialog -Selektor hinzufügen:

dialog {
  position: fixed;
  z-index: 999;
  inset-block-start: 30%;
  inset-inline-start: 50%;
  width: 300px;
  margin-inline-start: -150px;
}

Wenn das Modal sichtbar ist, sieht die Ausgabe wie in Abbildung 4-14 dargestellt aus.

Modal component with backdrop and stylings
Abbildung 4-14. Modale Komponente mit Hintergrund und Stylings

Wir haben gelernt, wie man eine wiederverwendbare Modal Komponente mit Teleport implementiert und haben verschiedene Anwendungsfälle mit den eingebauten <dialog> Elementfunktionen erforscht. Wir haben auch gelernt, wie man den ::backdrop CSS-Selektor verwendet, um den Hintergrund des Modals zu gestalten.

Wie du bemerkt hast, haben wir den Zielort div für das Modal so festgelegt, dass er ein direktes Kind von body ist, außerhalb des Vue-App-Eingabeelements <div id="app">. Was passiert, wenn wir das Ziel des Modals div innerhalb der Eingangskomponente App.vue der Vue-Anwendung verschieben wollen? Das werden wir im nächsten Abschnitt herausfinden.

Rendering-Problem mit Teleport

Um das Problem mit der Verwendung von Teleport zum Rendern des Modals innerhalb einer untergeordneten Komponente der Komponente App.vue zu verstehen, verschieben wir zunächst <div id="modal"></div> von index.html nach App.vue, nach der WithModalComponent Instanz :

<template>
  <section class="wrapper">
    <WithModalComponent />
  </section>
  <div id="modal"></div>
</template>

Nachdem du deine Anwendung ausgeführt hast, kannst du sehen, dass der Browser das Modal nicht rendert, egal wie oft du auf die Schaltfläche Open modal klickst. Und die Konsole zeigt den folgenden Fehler an:

Error message when rendering modal inside App.vue
Abbildung 4-15. Konsolenfehlermeldung beim Rendern des Modals innerhalb App.vue

Aufgrund des Vue-Mechanismus für die Rendering-Reihenfolge wartet das Elternteil, bis die Kinder gerendert sind, bevor es selbst gerendert wird. Die Kinder werden in der Reihenfolge gerendert, in der sie im Abschnitt template des Elternteils erscheinen. In diesem Szenario wird das Element WithModalComponent zuerst gerendert. Vue rendert also das Element <dialog> und beginnt damit, den Inhalt der Komponente an die Zielposition zu verschieben, bevor ParentComponent gerendert wird. Da ParentComponent jedoch noch darauf wartet, dass WithModalComponent sein Rendering beendet, existiert das Element <div id="modal"> noch nicht im DOM. Daher kann Vue die Zielposition nicht finden und die richtige Verschiebung nicht durchführen und das <dialog> Element nicht innerhalb des <div id="modal"> Elements rendern, daher der Fehler.

Ein Workaround, um diese Einschränkung zu umgehen, ist, das Zielelement<div id="modal"> vor WithModalComponent zu platzieren:

<template>
  <div id="modal"></div>
  <section class="wrapper">
    <WithModalComponent />
  </section>
</template>

Diese Lösung stellt sicher, dass das Ziel div verfügbar ist, bevor Vue das Element Modal rendert und den Inhalt verschiebt. Ein anderer Ansatz besteht darin, das disabled Attribut zu verwenden, um das Verschieben des Inhalts für Modal während des Renderns zu verschieben, bis der Nutzer auf die Schaltfläche Open modal klickt. Beide Optionen haben Vor- und Nachteile, und du solltest dich für diejenige entscheiden, die deinen Bedürfnissen am besten entspricht.

Die gängigste Lösung ist, das Zielelement als direktes Kind des body Elements einzufügen und es vom Vue-Rendering-Kontext zu isolieren.

Ein wesentlicher Vorteil der Verwendung von <Teleport> ist die Erzielung eines maximalen visuellen Anzeigeeffekts (z. B. Vollbildmodus, modal, Seitenleiste usw.) bei gleichzeitiger Beibehaltung der Codehierarchiestruktur, Komponentenisolierung und Lesbarkeit .

Zusammenfassung

In diesem Kapitel wurde das Konzept der verschiedenen Ansätze für die Kommunikation von Komponenten mit Hilfe der eingebauten Vue-Funktionen wie props, emits und provide/inject untersucht. Wir haben gelernt, wie wir diese Funktionen nutzen können, um Daten und Ereignisse zwischen Komponenten weiterzugeben, ohne den Datenflussmechanismus von Vue zu beeinträchtigen. Wir haben auch gelernt, wie man die Teleport-API verwendet, um ein Element außerhalb des DOM-Baums der übergeordneten Komponente zu rendern, während die Reihenfolge der Darstellung in der übergeordneten Komponente beibehalten wird <template>. <Teleport> ist von Vorteil für die Erstellung von Komponenten, die mit Ausrichtung auf das Hauptelement der Seite angezeigt werden müssen, wie z. B. Popups, Dialoge, Modals usw.

Im nächsten Kapitel werden wir mehr über die Composition API erfahren und wie man sie nutzt, um Vue-Komponenten zusammenzustellen.

Get Vue lernen now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.