Liste Rendering
v-for
Wir können die v-for
Direktive verwenden, um eine Liste von Elementen auf der Grundlage eines Arrays darzustellen. Die v-for
Direktive erfordert eine spezielle Syntax in der Form item in items
, wobei items
as Quelldaten-Array ist und item
ein alias für das Array-Element ist, über das iteriert wird:
js
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
template
<li v-for="item in items">
{{ item.message }}
</li>
Innerhalb des Bereichs v-for
haben die Schablonenausdrücke Zugriff auf alle Eigenschaften des übergeordneten Bereichs. Darüber hinaus unterstützt v-for
auch einen optionalen zweiten Alias für den Index des aktuellen Elements:
js
const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
template
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
Die Variablenzuordnung von v-for
ähnelt dem folgenden JavaScript:
js
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// has access to outer scope `parentMessage`
// but `item` and `index` are only available in here
console.log(parentMessage, item.message, index)
})
Beachten Sie, dass der v-for
Wert mit der Funktionssignatur des forEach
Callbacks übereinstimmt. In der Tat können Sie die Destrukturierung auf den v-for
Element-Alias anwenden, ähnlich wie bei der Destrukturierung von Funktionsargumenten:
template
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- with index alias -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
Bei verschachtelten v-for
, Bereichen funktioniert das Scoping ähnlich wie bei verschachtelten Funktionen. Jeder v-for
Bereich hat Zugriff auf übergeordnete Bereiche:
template
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
Sie können auch of
als Begrenzungszeichen anstelle von in
verwenden, so dass es näher an der JavaScript-Syntax für Iteratoren ist:
template
<div v-for="item of items"></div>
v-for
mit einem Objekt
Sie können auch v-for
verwenden, um durch die Eigenschaften eines Objekts zu iterieren. Die Iterationsreihenfolge basiert auf dem Ergebnis des Aufrufs von Object.keys()
für das Objekt:
js
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
template
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
Sie können auch einen zweiten Alias für den Namen der Eigenschaft (auch bekannt als Schlüssel) angeben:
template
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
Und eine weitere für den Index:
template
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
v-for
mit einem Bereich
v-for
kann auch eine ganze Zahl annehmen. In diesem Fall wird die Vorlage so oft wiederholt, basierend auf einem Bereich von 1...n
.
template
<span v-for="n in 10">{{ n }}</span>
Man beachte, dass n
mit einem Anfangswert von 1
anstelle von of 0
beginnt.
v-for
on <template>
Ähnlich wie bei der Vorlage v-if
können Sie auch ein <template>
Tag mit v-for
verwenden, um einen Block mit mehreren Elementen darzustellen. Zum Beispiel:
template
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for
mit v-if
:::Warnung Hinweis Es wird nicht empfohlen, v-if
und v-for
für dasselbe Element zu verwenden, da sie implizit Vorrang haben. Siehe style guide für Details. :::
Wenn sie auf demselben Knoten existieren, hat v-if
eine höhere Priorität als v-for
. Das bedeutet, dass die v-if
Bedingung keinen Zugriff auf Variablen aus dem Bereich von v-for
hat:
template
<!--
Dies führt zu einem Fehler, da die Eigenschaft "todo"
in der Instanz nicht definiert ist.
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
Dies kann behoben werden, indem v-for
in ein umhüllendes <template>
-Tag verschoben wird (was auch eindeutiger ist):
template
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
Aufrechterhaltung des Zustands mit key
Wenn Vue eine Liste von Elementen aktualisiert, die mit v-for
gerendert werden, verwendet es standardmäßig eine "in-place patch" Strategie. Wenn sich die Reihenfolge der Datenelemente geändert hat, wird Vue, anstatt die DOM-Elemente zu verschieben, um die Reihenfolge der Elemente anzupassen, jedes Element an Ort und Stelle patchen und sicherstellen, dass es widerspiegelt, was an diesem bestimmten Index gerendert werden sollte.
Dieser Standardmodus ist effizient, aber nur geeignet, wenn die Ausgabe der Liste nicht auf dem Zustand der untergeordneten Komponenten oder dem temporären DOM-Zustand (z. B. Formulareingabewerte) beruht.
Um Vue einen Hinweis zu geben, so dass es die Identität jedes Knotens verfolgen und somit bestehende Elemente wiederverwenden und neu anordnen kann, müssen Sie ein eindeutiges key
-Attribut für jedes Element angeben:
template
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>
Bei der Verwendung von <template v-for>
, sollte der key
auf dem <template>
Container platziert werden::
template
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
:::Tipp Hinweis key
ist hier ein spezielles Attribut, das mit v-bind
gebunden wird. Es sollte nicht mit der Eigenschaftsvariable "key" verwechselt werden, wenn v-for
mit einem Objekt. :::
Es wird empfohlen ein key
Attribut mit v-for
bereitzustellen, wann immer dies möglich ist, es sei denn, der iterierte DOM-Inhalt ist einfach (d.h. er enthält keine Komponenten oder zustandsbehafteten DOM-Elemente), oder Sie verlassen sich absichtlich auf das Standardverhalten, um die Leistung zu steigern.
Die key
Bindung erwartet primitive Werte - d.h. Strings und Zahlen. Verwenden Sie keine Objekte als v-for
Schlüssel. Für die detaillierte Verwendung des key
Attributs, lesen Sie bitte die key
API Dokumentation.
v-for
mit einer Komponente
Dieser Abschnitt setzt Kenntnisse über [Komponenten].(/guide/essentials/component-basics) voraus. Sie können es auch überspringen und später wiederkommen.
Sie können v-for
direkt auf eine Komponente anwenden, wie jedes normale Element (vergessen Sie nicht, einen key
anzugeben):
template
<MyComponent v-for="item in items" :key="item.id" />
Dadurch werden jedoch nicht automatisch Daten an die Komponente übergeben, da Komponenten über eigene isolierte Bereiche verfügen. Um die iterierten Daten an die Komponente zu übergeben, sollten wir auch props verwenden:
template
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
Der Grund dafür, dass item
nicht automatisch in die Komponente injiziert wird, ist, dass die Komponente dadurch eng an die Funktionsweise von v-for
gekoppelt ist. Wenn explizit angegeben wird, woher die Daten kommen, kann die Komponente in anderen Situationen wiederverwendet werden.
Siehe dieses Beispiel für eine einfache ToDo-Liste um zu sehen, wie eine Liste von Komponenten mit v-for
gerendert werden kann, wobei jeder Instanz unterschiedliche Daten übergeben werden.
Erkennung von Array-Änderungen
Mutationsmethoden
Vue ist in der Lage zu erkennen, wann die Mutationsmethoden eines reaktiven Arrays aufgerufen werden und löst die notwendigen Aktualisierungen aus. Diese Mutationsmethoden sind:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Ersetzen eines Arrays
Mutationsmethoden verändern, wie der Name schon sagt, das ursprüngliche Array, auf dem sie aufgerufen werden. Im Vergleich dazu gibt es auch nicht-mutierende Methoden, z.B. filter()
, concat()
und slice()
, die das ursprüngliche Array nicht verändern, sondern immer ein neues Array zurückgeben. Wenn man mit nicht-mutierenden Methoden arbeitet, sollte man das alte Array durch das neue ersetzen:
js
// `items` is a ref with array value
items.value = items.value.filter((item) => item.message.match(/Foo/))
Man könnte meinen, dass dies dazu führt, dass Vue das bestehende DOM wegwirft und die gesamte Liste neu gerendert wird - zum Glück ist das nicht der Fall. Vue implementiert einige intelligente Heuristiken, um die Wiederverwendung von DOM-Elementen zu maximieren, so dass das Ersetzen eines Arrays durch ein anderes Array mit überlappenden Objekten eine sehr effiziente Operation ist.
Gefilterte/sortierte Ergebnisse anzeigen
Manchmal möchte man eine gefilterte oder sortierte Version eines Arrays anzeigen, ohne die Originaldaten zu verändern oder zurückzusetzen. In diesem Fall können Sie eine berechnete Eigenschaft erstellen, die das gefilterte oder sortierte Array zurückgibt.
Zum Beispiel:
js
const numbers = ref([1, 2, 3, 4, 5])
const evenNumbers = computed(() => {
return numbers.value.filter((n) => n % 2 === 0)
})
template
<li v-for="n in evenNumbers">{{ n }}</li>
In Situationen, in denen berechnete Eigenschaften nicht durchführbar sind (z. B. innerhalb von verschachtelten v-for
Schleifen), können Sie eine Methode verwenden:
js
const sets = ref([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]
])
function even(numbers) {
return numbers.filter((number) => number % 2 === 0)
}
template
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)">{{ n }}</li>
</ul>
Seien Sie vorsichtig mit reverse()
und sort()
in einer berechneten Eigenschaft! Diese beiden Methoden verändern das ursprüngliche Array, was in berechneten Gettern vermieden werden sollte. Erstellen Sie eine Kopie des ursprünglichen Arrays, bevor Sie diese Methoden aufrufen:
diff
- return numbers.reverse()
+ return [...numbers].reverse()