Vykreslování seznamu
v-for
Pro vykreslení senzamu založeného na hodnotách pole můžeme použít direktivu v-for
. Zápis v-for
vyžaduje speciální syntaxi ve formě item in items
, kde items
je zdrojové datové pole a item
je alias pro prvek pole, přes které se iteruje:
js
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
template
<li v-for="item in items">
{{ item.message }}
</li>
Uvnitř elementu s v-for
mají výrazy šablony přístup ke všem vlastnostem nadřazeného scope. Navíc v-for
podporuje ještě volitelný druhý alias pro index aktuální položky:
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>
Scope proměnné z v-for
je obdobný jako v následujícímu JavaScript kódu:
js
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// má přístup do vnejšího scope`parentMessage`
// ale `item` a `index` jsou dostupné pouze zde
console.log(parentMessage, item.message, index)
})
Všimněte si, že se hodnota v-for
shoduje s definicí callback funkce forEach
. Dokonce můžete použít destrukturování na alias položky v-for
podobně jako na parametry funkce:
template
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- with index alias -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
Pro vnořené v-for
funguje scope také stejně jako ve vnořených funkcích. Každý scope v-for
má přístup do rodičovského scope:
template
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
Aby byl zápis bližší JavaScript syntaxi pro iterátory, můžete také místo in
použít of
:
template
<div v-for="item of items"></div>
v-for
nad objektem
Direktivu v-for
můžete také použít pro iteraci nad vlastnostmi objektu. Pořadí iterace bude záviset na výsledku volání funkce Object.values()
na daný 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>
Můžete také úvést druhý alias (klíč) pro název vlastnosti:
template
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
A ještě další pro její pořadí:
template
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
v-for
nad rozsahem hodnot
v-for
akceptuje jako parametr i číslo. V tomto případě se bude šablona opakovat n-krát, na základě rozsahu 1...n
.
template
<span v-for="n in 10">{{ n }}</span>
Dejte pozor, že n
začíná s úvodníh hodnotou 1
místo obvyklé 0
.
v-for
nad <template>
Podobně jako u v-if
, je možné tag <template>
použití i s v-for
pro vícenásobné vykreslení bloku. Například:
template
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for
s v-if
Poznámka
Nedoporučuje se používat v-if
a v-for
na stejném prvku kvůli jejich implicitní prioritě. Podrobnosti naleznete v Průvodci stylováním.
Když existují na stejném elementu, v-if
má vyšší prioritu než v-for
. To znamená, že podmínka v-if
nebude mít přístup k proměnným z v-for
scope:
template
<!--
Toto vyvolá výjimku, protože "toto"
není definovaná jako proměnná instance
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
Toto lze napravit přesunutím v-for
do obalujícího <template>
tagu (což je také přehlednější):
template
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
Udržování stavu pomocí key
Když Vue aktualizuje seznam prvků vykreslených pomocí v-for
, ve výchozím nastavení používá strategii „opravy na místě“. Pokud se pořadí datových položek změnilo, namísto přesování prvků DOM tak, aby odpovídaly pořadí položek, Vue každý prvek opraví na jeho místě a zajistí, aby odrážel to, co by se na daném místě mělo vykreslit.
Tento výchozí režim je efektivní, ale vhodný pouze tehdy, když výsledek vykreslení vašeho seznamu nezávisí na stavu podřízené komponenty nebo dočasném stavu DOM (např. vstupní hodnoty formulářů).
Chcete-li Vue poskytnout nápovědu, aby mohlo sledovat identitu každého uzlu, a tedy znovupoužít a změnit pořadí existujících prvků, musíte pro každou položku poskytnout jedinečný atribut key
:
template
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>
Při použití <template v-for>
, by měl být key
umístěn do <template>
tagu:
template
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
Poznámka
Zde uvedený key
je speciální atribut propojený s v-bind
. Nemělo by se zaměňovat s klíčem pro vlastnosti při použití v-for
nad objektem.
Je doporučeno použití atributu key
s v-for
, kdykoli je to možné. Výjimkou mohou být situace, kdy je iterovaný obsah DOM velmi jednoduchý (tj. neobsahuje žádné komponenty nebo stavové elementy DOM), nebo se záměrně spoléháte na výchozí chování pro zvýšení výkonu.
Direktiva key
očekává vazbu na primitivní hodnoty – tedy string a number. Nepoužívejte jako klíče v-for
objekty. Podrobné použití atributu key
naleznete v API dokumentaci pro key
.
v-for
nad komponentou
Tato sekce předpokládá znalost základů komponent. Klidně ji teď přeskočte a vraťte se později.
Je možné použít v-for
přímo na komponentu, jako by to byl jiný standardní element (nezapomeňte definovat key
):
template
<MyComponent v-for="item in items" :key="item.id" />
To však komponentě automaticky nepředá žádná data, protože komponenty mají své vlastní izolované scope. Abychom předali do komponenty iterovaná data, měli bychom použít také vlastnosti (props):
template
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
Důvodem, proč se item
do komponenty automaticky nevkládá, je, že díky tomu by byla komponenta pevně spojena s tím, jak funguje v-for
. Určovat explicitně odkud data pocházejí umožňuje, že je komponenta znovupoužitelná i v jiných situacích.
Podívejte se na tento příklad jednoduchého TODO listu, abyste viděli, jak vykreslit list komponent pomocí v-for
s předáním různých dat do každé instance.
Detekce změny pole
Změnové funkce
Vue umí detekovat, když jsou volány změnové funkce reaktivního pole, a vyvolat potřebné aktualizace. Tyto změnové funkce jsou:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Nahrazení pole
Změnové funkce, jak název napovídá, mění původní pole, na kterém jsou volány. Pro srovnání existují i funkce, které pole nemění, např. filter()
, concat()
a slice()
, které nemění původní pole, ale vždy vrátí nové pole. Při práci s těmito funkcemi bychom měli staré pole nahradit novým:
js
// `items` je ref obsahující pole
items.value = items.value.filter((item) => item.message.match(/Foo/))
Možná byste si mysleli, že to způsobí, že Vue zahodí stávající DOM a vykreslí celý seznam znovu – naštěstí tomu tak není. Vue implementuje některé chytré heuristiky pro maximalizaci znovupoužití DOM elementů, takže nahrazení jednoho pole jiným polem obsahujícím překrývající se objekty je velmi efektivní operace.
Zobrazení filtrovaných/seřazených výsledků
Někdy chceme zobrazit filtrovanou nebo seřazenou verzi pole, aniž bychom skutečně měnili nebo resetovali původní data. V tomto případě můžete vytvořit computed proměnnou, která vrátí pole filtrované nebo seřazené.
Například:
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>
V situacích, kdy computed proměnné nejsou proveditelné (např. uvnitř vnořených v-for
cyklů), můžete použít funkci:
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>
U computed proměnných buďte opatrní s reverse()
a sort()
! Tyto dvě funkce mění původní pole, čemuž je u computed getterů třeba se vyhnout. Před voláním těchto funkcí vytvořte kopii původního pole:
diff
- return numbers.reverse()
+ return [...numbers].reverse()