Interpretação de Lista
v-for
Nós podemos utilizar a diretiva v-for
para interpretar uma lista de itens baseados em um arranjo. A diretiva v-for
exije uma sintaxe especial na forma de item in items
, onde items
é o arranjo de dados de origem e o item
é um pseudónimo para o elemento do arranjo sobre qual é interado:
js
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
template
<li v-for="item in items">
{{ item.message }}
</li>
Dentro do escopo de v-for
, as expressões do modelo de marcação tem acesso a todas propriedades do escopo do pai. Além disto, a v-for
também suporta um segundo pseudónimo opcional para índice do item atual:
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>
O escopo de variável da v-for
é similar ao seguinte código de JavaScript:
js
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// tem acesso ao `parentMessage` do escopo externo
// mas `item` e `index` apenas estão disponíveis aqui
console.log(parentMessage, item.message, index)
})
Repare como o valor de v-for
corresponde a assinatura de função da resposta de forEach
. Na realidade, podes utilizar a desestruturação no pseudónimo do item de v-for
similar a desestruturação de argumentos de função:
template
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- with index alias -->
<!-- com o pseudónimo de índice ("index") -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
Para v-for
encaixados, o escopo também funciona de maneira similar as funções encaixadas. Cada escope de v-for
em acesso aos escopos pai:
template
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
Tu também podes utilizar of
como delimitador no lugar de in
, para que esteja mais próximo da sintaxe da JavaScript para iteradores:
template
<div v-for="item of items"></div>
v-for
com um Objeto
Tu também podes utilizar a v-for
para iterar através das propriedades de um objeto. A ordem de iteração será baseada no resultado da chamada de Object.keys()
sobre o objeto:
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>
Tu também podes fornecer um segundo pseudónimo para o nome da propriedade (também conhecido como chave):
template
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
E um outro para o índice:
template
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
v-for
com um Limite
A v-for
também pode aceitar um inteiro. Neste caso repetirá o modelo de marcação que aquelas muitas vezes, baseado em um limite de 1...n
.
template
<span v-for="n in 10">{{ n }}</span>
Nota que aqui n
começa com um valor inicial de 1
no lugar de 0
.
v-for
no <template>
Semelhante a v-if
do modelo de marcação, também podes utilizar o marcador <template>
para interpretar um bloco com vários elementos. Por exemplo:
template
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for
com v-if
AVISO
Não é recomendado utilizar v-if
e v-for
no mesmo elemento devido a precedência implicita. Consulte o guia de estilo para obter mais detalhes.
Quando elas existem no mesmo nó, a v-if
tem uma prioridade mais alta do que a v-for
. Que significa que a condição v-if
não terá acesso as variáveis do escope do v-for
:
template
<!--
Isto lançará um erro porque a propriedade "todo"
não está definida na instância
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
Isto pode ser corrigido movendo v-for
para um marcodor <template>
de embrulho (que também é mais explicito):
template
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
Mantendo o Estado com key
Quando a Vue está atualizando um lista de elementos interpretados com a v-for
, por padrão ela utiliza uma estratégia de "remendar no lugar (in-place patch)". Se a ordem dos itens de dados mudou, no lugar de mover os elementos do DOM para corresponder a ordem dos itens, a Vue remendará cada elemento no lugar e certificar-se de que ela refleta o que deveria ser interpretado naquele índice particular.
Este modo padrão é eficiente, mas só é adequando quando o resultado da interpretação da tua lista não depender do estado do componente filho ou do estado temporário do DOM (por exemplo, valores de entrada de formulário).
Para dar a Vue uma sugestão para que ela possa rastreiar qualquer identidade do nó, e assim reutilizar e reorganizar os elementos existente, precisas fornecer um atributo key
único para cada item:
template
<div v-for="item in items" :key="item.id">
<!-- content -->
<!-- conteúdo -->
</div>
Quando estiveres utilizando <template v-for>
, o key
deve ser colocado no contentor <template>
:
template
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
NOTA
Aqui key
é um atributo especial sendo vinculado com a v-bind
. Ela não deveria ser confundida com a variável chave (key
) de propriedade quando estiveres utilizando a v-for
com um objeto.
É recomendado fornecer um atributo key
com a v-for
sempre que possível, a menos que o conteúdo de DOM iterado seja simples (por exemplo, não contém quaisquer componentes ou elementos de DOM com conteúdo), estás intencionalmente confiando no comportamento padrão para ganhos de desempenho.
O vinculação de key
aguarda por valores primitivos - por exemplo, sequências de caracteres e números. Não utilize objetos como chaves de v-for
. Para utilização detalhada do atributo key
, favor de consultar a documentação da API de key
.
v-for
com um Componente
Esta secção presume conhecimento de Componentes. Esteja livre para ignorá-la e voltar mais tarde.
Tu podes utilizar a v-for
diretamente sobre um componente, tal como qualquer elemento normal (não te esqueças de fornecer um key
):
template
<MyComponent v-for="item in items" :key="item.id" />
No entanto, isto não passará quaisquer dados automaticamente para o componente, porque os componentes têm seus próprios escopos isolados. Para passar o dado iterado para dentro do componente, também devemos utilizar as propriedades:
template
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
A razão para não injetar automaticamte o item
para dentro do componente é porque isto torna o componente fortemente acoplado à como a v-for
funciona. Ser explicito a respeito de onde os teus dados vem torna o componente reutilizável em outras situações.
Consulte este exemplo de uma lista de afazeres simples para veres como interpretar uma lista de componentes utilizando a v-for
, passando diferentes dados para cada instância.
Deteção de Mudança de Arranjo
Métodos de Mutação
A Vue é capaz de detetar quando métodos de mutação de um arranjo reativo são chamados e aciona as atualizações necessárias. Estes métodos de mutação são:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Substituindo um Arranjo
Os métodos de mutação, como o nome sugere, alteram o arranjo original sobre o qual eles são chamados. Em comparação, também existem métodos que não realizam mutação, por exemplo, filter()
, concat()
e slice()
, que não alteram o arranjo original mas sempre retornam um arranjo novo. Quando estivermos trabalhando como métodos que não realizam mutação, devemos substituir o arranjo antigo com o arranjo novo:
js
// `items` é uma referência com valor de arranjo
items.value = items.value.filter((item) => item.message.match(/Foo/))
Tu podes achar que isto fará a Vue deixar fora o DOM existente e reinterpretar a lista inteira - felizmente, este não é o caso. A Vue implementa algumas heurísticas inteligentes para maximizar a reutilização do elemento do DOM, assim substituir um arranjo com um outro arranjo contendo objetos que se sobrepõem é uma operação muito eficiente.
Exibindo Resultados Filtrados ou Organizados
Algumas vezes queremos exibir uma versão filtrada ou organizada de um arranjo sem alterar ou redefinir os dados originais. Neste caso, podes criar uma propriedade computada que retorna o arranjo filtrado ou organizado.
Por exemplo:
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>
Em situações onde as propriedades computadas não são viáveis (por exemplo, dentro de laços v-for
encaixados), podes utilizar um método:
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>
Tenha cuidado com reverse()
e sort()
dentro de uma propriedade computada! Estes dois métodos alterarão o arranjo original, o que deve ser evitado nos recuperadores computados. Crie uma copia do arranjo original antes de chamar estes métodos:
diff
- return numbers.reverse()
+ return [...numbers].reverse()