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