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()