Rendering delle Liste
v-for
Per mostrare una lista di elementi basati su un array possiamo utilizzare la direttiva v-for. La direttiva v-for richiede una sintassi speciale nella forma di item in items, dove items è l'array di dati sorgente e item è un alias per l'elemento dell'array su cui si sta iterando:
js
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])template
<li v-for="item in items">
{{ item.message }}
</li>All'interno dello scope di v-for, le espressioni del template hanno accesso a tutte le proprietà dello scope del genitore. Inoltre, v-for supporta anche un secondo alias opzionale per l'indice dell'elemento corrente:
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>Il contesto delle variabili in v-for è simile al seguente JavaScript:
js
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// ha accesso allo scope/contesto esterno per `parentMessage`
// ma `item` e `index` sono disponibili solo qui
console.log(parentMessage, item.message, index)
})Nota come il valore v-for corrisponda alla dichiarazione della funzione nella callback di forEach. Puoi utilizzare, infatti, il destructuring sull'alias dell'elemento v-for in modo simile al destructuring degli argomenti della funzione:
template
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- con un alias per index -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>Per v-for annidati, anche lo scope funziona in modo simile alle funzioni annidate. Ogni scope di v-for ha accesso agli scope dei genitori:
template
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>È possibile utilizzare anche of come delimitatore al posto di in, così da avvicinarsi maggiormente alla sintassi di JavaScript per gli iteratori:
template
<div v-for="item of items"></div>v-for con un Oggetto
Puoi anche utilizzare v-for per iterare attraverso le proprietà di un oggetto. L'ordine dell'iterazione sarà basato sul risultato dell'invocazione di Object.keys() sull'oggetto:
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>Puoi anche fornire un secondo alias per il nome della proprietà (anche noto come key):
template
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>E un altro per l'indice (index):
template
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>v-for con un Intervallo
v-for può accettare anche un numero intero. In questo caso, ripeterà il template quel numero di volte, basandosi su un intervallo da 1 a n.
template
<span v-for="n in 10">{{ n }}</span>Nota che n con un valore iniziale di 1 al posto di 0.
v-for su <template>
Come con v-if, nel template puoi usare un tag <template> anche con v-for per renderizzare un blocco di elementi multipli. Ad esempio:
template
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>v-for con v-if
Nota
Non è consigliato utilizzare v-if e v-for sullo stesso elemento a causa della precedenza implicita. Fare riferimento alla guida di stile per i dettagli.
Quando esistono sullo stesso nodo, v-if ha una priorità maggiore rispetto a v-for. Ciò significa che la condizione v-if non avrà accesso alle variabili dallo scope di v-for:
template
<!--
Questo genererà un errore perché la proprietà "todo"
non è definita sull'istanza.
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>Questo problema può essere risolto spostando v-for in un tag <template> contenitore (che è anche più esplicito):
template
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>Mantenere lo Stato con key
Quando Vue aggiorna un elenco di elementi resi con v-for, di default utilizza una strategia di "correzione in loco" (in-place patch). Se l'ordine degli elementi dei dati viene modificato, invece di spostare gli elementi DOM per far corrispondere l'ordine degli elementi, Vue correggerà in-place ogni elemento e si assicurerà che rifletta ciò che dovrebbe essere reso in quel particolare indice.
Questa modalità predefinita è efficiente, ma è adatta solo quando l'output della visualizzazione del tuo elenco non dipende dallo stato del componente figlio o dallo stato temporaneo del DOM (ad es. valori di input del modulo).
Per permettere a Vue di identificare ogni nodo cosi da poter riutilizzare e riordinare gli elementi esistenti, è necessario fornire un attributo key unico per ogni elemento:
template
<div v-for="item in items" :key="item.id">
<!-- contenuto -->
</div>Quando si utilizza <template v-for>, la key deve essere posizionata sul contenitore <template>:
template
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>Nota
L'attributo key qui è uno speciale attributo legato a v-bind, e non va confuso con la "chiave" della proprietà di un oggetto, come quando si utilizza v-for con un oggetto.
Si raccomanda di fornire un attributo key con v-for ogni volta che è possibile, a meno che il contenuto DOM iterato non sia semplice (cioè non contenga componenti o elementi DOM con stato), o si stia volutamente facendo affidamento sul comportamento predefinito per aumentare le prestazioni.
Il binding della key si aspetta valori primitivi, cioè stringhe e numeri. Non utilizzare oggetti come chiavi per v-for. Per un utilizzo dettagliato dell'attributo key, si prega di consultare la documentazione dell'API key.
v-for con un Componente
Questa sezione presuppone la conoscenza dei Componenti. Sentiti libero di saltarla e tornare in seguito.
Puoi utilizzare direttamente v-for su un componente, come su un qualsiasi elemento, ma non dimenticare di fornire una key:
template
<MyComponent v-for="item in items" :key="item.id" />Tuttavia, questo non passerà alcun dato al componente in modo automatico, poiché i componenti hanno i propri scope isolati. Per passare i dati iterati al componente, dovremmo utilizzare anche le props:
template
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>La ragione per non iniettare item nel componente automaticamente è che ciò renderebbe il componente strettamente accoppiato al funzionamento di v-for. Essere chiari sull'origine dei dati rende il componente adattabile a diverse situazioni.
Guarda questo esempio di una semplice lista di todo per vedere come rendere un elenco di componenti utilizzando v-for, passando dati diversi a ogni istanza.
Rilevare le modifiche all'Array
Metodi di mutazione
Vue è in grado di rilevare quando vengono chiamati i metodi di mutazione di un array reattivo e di attivare gli aggiornamenti necessari. Questi metodi di mutazione sono:
push()pop()shift()unshift()splice()sort()reverse()
Sostituire un Array
I metodi di mutazione (Mutation methods), come suggerisce il nome, modificano l'array originale su cui vengono chiamati. Esistono anche metodi non mutanti, come filter(), concat() e slice(), che non modificano l'array originale ma restituiscono sempre un nuovo array. Quando si lavora con metodi non mutanti, si dovrebbe sostituire il vecchio array con uno nuovo:
js
// `items` è un ref con valore di array
items.value = items.value.filter((item) => item.message.match(/Foo/))Potresti pensare che ciò costringerà Vue a scartare il DOM esistente e a ri-renderizzare l'intero elenco - fortunatamente, non è così. Vue implementa alcune euristiche intelligenti per massimizzare il riutilizzo degli elementi del DOM, quindi sostituire un array con un altro array contenente oggetti che si sovrappongono è un'operazione molto efficiente.
Visualizzare Risultati Filtrati/Ordinati
A volte vogliamo visualizzare una versione filtrata o ordinata di un array senza effettivamente modificare o reimpostare i dati originali. In questo caso puoi creare una proprietà calcolata (computed property) che restituisce l'array filtrato o ordinato.
Ad esempio:
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>Nelle situazioni in cui le computed properties non sono utilizzabili (ad es. all'interno di cicli v-for annidati), è possibile utilizzare un metodo:
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>Fai attenzione con reverse() e sort() in una computed property! Questi due metodi modificheranno l'array originale, il che dovrebbe essere evitato nei getter delle computed property. Crea una copia dell'array originale prima di chiamare questi metodi:
diff
- return numbers.reverse()
+ return [...numbers].reverse()