Clique aqui para a documentação da v3.x.

Você está navegando a documentação da v2.x e anterior. Para a v3.x, clique aqui.

Renderização de Listas

Array em Elementos com v-for

Podemos utilizar a diretiva v-for para renderizar uma lista de elementos com base nos dados de um Array. A diretiva requer uma sintaxe especial na forma de item in items, onde items é a fonte de dados e item é um apelido para o elemento que estiver sendo iterado:

<ul id="example-1">
  <li v-for="item in items" :key="item.message">
    {{ item.message }}
  </li>
</ul>
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Algo' },
      { message: 'Outro' }
    ]
  }
})

Resultado:

Dentro de blocos v-for temos acesso completo às propriedades do escopo pai. Também há suporte a um segundo argumento opcional para o índice do item atual.

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Pai',
    items: [
      { message: 'Algo' },
      { message: 'Outro' }
    ]
  }
})

Resultado:

Também é possível utilizar of como delimitador, em vez de in, de forma que fique mais próximo da sintaxe de iteradores do JavaScript:

<div v-for="item of items"></div>

Objetos em v-for

Você pode utilizar v-for para iterar através das propriedades de um objeto.

<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      title: 'Como fazer listas no Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
})

Resultado:

Você também pode oferecer um segundo argumento para o nome da propriedade (também conhecido como chave):

<div v-for="(value, name) in object">
  {{ name }}: {{ value }}
</div>
{{ name }}: {{ value }}

E ainda um terceiro para o índice:

<div v-for="(value, name, index) in object">
  {{ index }}. {{ name }}: {{ value }}
</div>
{{ index }}. {{ name }}: {{ value }}

Quando estiver iterando sobre um objeto, a ordem é baseada na enumeração do Object.keys(), a qual não é garantidamente consistente entre implementações distintas de motores JavaScript.

Manutenção de Estado

Quando Vue está atualizando uma lista de elementos renderizados com v-for, por padrão se utiliza de uma estratégia de “remendo local”. Se a ordem dos itens de dados tiver mudado, em vez de mover os elementos DOM para combinar com a nova ordem, Vue remendará o conteúdo de cada elemento em seu local atual, garantindo que o resultado reflita o que precisa ser renderizado em cada índice em particular. Isto é similar ao comportamento oferecido por track-by="$index" no Vue 1.x.

Este modo padrão é eficiente, mas adequado apenas quando seu resultado de renderização não se apoiar em estado de componentes filhos ou estado de DOM temporário (como valores de campos de formulário).

Para dar uma dica ao Vue e ele poder rastrear a identidade de cada nó e assim reutilizar e reordenar elementos existentes, defina um atributo key único para cada item.

<div v-for="item in items" v-bind:key="item.id">
  <!-- conteúdo -->
</div>

De fato, é recomendado oferecer um atributo key para v-for sempre que possível, a menos que esteja iterando conteúdo DOM simples, ou esteja intencionalmente se apoiando no comportamento padrão para ganho de desempenho.

Por ser um mecanismo genérico do Vue para identificar nós, key também tem outras utilidades não especificamente associadas ao v-for, como veremos futuramente neste guia.

Não use valores não primitivos como objetos e arrays como chaves para v-for. Use string ou valores numéricos.

Para uso detalhado do atributo key, por favor veja a documentação da API key.

Detectando Mudanças em Arrays

Métodos de Mutação

Vue envolve automaticamente os métodos de mutação de um Array observado, de forma que dispare alterações na interface. Os métodos englobados são:

Você pode abrir o console e brincar com os items dos exemplos anteriores, chamando seus métodos de mutação. Por exemplo: example1.items.push({ message: 'Novo' }).

Substituindo um Array

Métodos de mutação, como o nome sugere, mudam o Array original no qual são chamados. Em comparação, também há métodos sem mutação, como filter(), concat() e slice(), que não modificam o Array original, mas sim retornam um novo Array. Ao trabalhar com métodos sem mutação, você pode substituir o Array antigo pelo novo:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Algo/)
})

Você pode pensar que isto fará o Vue jogar fora todo o DOM existente e “re-renderizar” a lista toda - por sorte, não é o caso. Vue implementa algumas heurísticas inteligentes para maximizar a reutilização dos elementos DOM, assim sobrescrever um Array com outro, contendo elementos subjacentes, é uma operação muito eficiente.

Limitações

Por limitações no JavaScript, existem tipos de mudanças que o Vue não pode detectar em arrays e objetos. Esses são discutidos na seção reatividade.

Mostrando Resultados Filtrados/Ordenados

Às vezes, queremos exibir uma versão filtrada ou ordenada de um Array sem efetivamente mudar ou reiniciar seus dados originais. Neste caso, você pode criar um dado computado que retorna um Array filtrado ou ordenado.

Por exemplo:

<li v-for="n in evenNumbers">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

Em situações onde dados computados não são factíveis (por exemplo, em repetições v-for aninhadas), você pode usar um método:

<ul v-for="set in sets">
  <li v-for="n in even(set)">{{ n }}</li>
</ul>
data: {
  sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

Intervalo Numérico no v-for

O v-for pode aceitar um número inteiro. O template se repetirá este número de vezes.

<div>
  <span v-for="n in 10">{{ n }} </span>
</div>

Resultado:

{{ n }}

Utilizando <template> com v-for

Similar ao uso de template com v-if, você pode usar <template> com v-for para renderizar blocos de múltiplos elementos sem um elemento pai repetitivo. Exemplo:

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

Utilizando v-if com v-for

Note que não é recomendado usar v-if e v-for juntos. Consulte o guia de estilos para detalhes.

Quando existentes em um mesmo nó, v-for tem maior prioridade que v-if. Isto significa que v-if será executado separadamente a cada iteração da repetição. Isto pode ser útil se quiser renderizar nós condicionalmente para apenas alguns itens, como abaixo:

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

Este exemplo renderizaria apenas as tarefas não marcadas como completas.

Se, em vez disso, sua intenção for condicionalmente pular toda a execução da repetição, você pode colocar o v-if em um elemento envolvendo o bloco (ou <template>). Por exemplo:

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>Não há tarefas a fazer!</p>

Componentes com v-for

Caso ainda não tenha lido sobre Componentes, sinta-se livre para pular e voltar depois.

Você pode usar v-for diretamente em componentes personalizados de maneira comum:

<my-component v-for="item in items" :key="item.id"></my-component>

Em 2.2.0+, ao usar v-for com um componente, um atributo key é obrigatório.

Observe, entretanto, que isto não passa automaticamente qualquer dado ao componente, pois componentes possuem seus próprios escopos isolados. Para passar dados iterados para dentro do componente, devemos utilizar Propriedades:

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>

A razão para não injetarmos automaticamente item dentro do componente é evitar que ele fique fortemente acoplado ao funcionamento do v-for. Sendo explícito sobre quais dados especificamente são introduzidos, tornamos o componente reutilizável em outras situações.

Aqui temos um exemplo de uma lista de tarefas simples usando componentes:

<div id="todo-list-example">
  <form v-on:submit.prevent="addNewTodo">
    <label for="new-todo">Tarefa:</label>
    <input
      v-model="newTodoText"
      id="new-todo"
      placeholder="Ex.: Alimentar o gato"
    >
    <button>Adicionar</button>
  </form>
  <ul>
    <li
      is="todo-item"
      v-for="(todo, index) in todos"
      v-bind:key="todo.id"
      v-bind:title="todo.title"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>
</div>

Observe o atributo is="todo-item". Ele é necessario em templates DOM, porque somente o elemento <li> é valido dentro de um <ul>. Ele faz o mesmo que <todo-item>, mas funciona em torno de um potencial erro do navegador. Veja DOM Template Parsing Caveats para saber mais.

Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">Remove</button>\
    </li>\
  ',
  props: ['title']
})

new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      {
        id: 1,
        title: 'Lavar os pratos',
      },
      {
        id: 2,
        title: 'Tirar o lixo',
      },
      {
        id: 3,
        title: 'Cortar a grama'
      }
    ],
    nextTodoId: 4
  },
  methods: {
    addNewTodo: function () {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})