Skip to content

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' }])
js
data() {
  return {
    items: [{ 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' }])
js
data() {
  return {
    parentMessage: 'Parent',
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}
template
<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
  • Parent - 0 - Foo
  • Parent - 1 - Bar
  • 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'
    })
    js
    data() {
      return {
        myObject: {
          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.

    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/))
    js
    this.items = this.items.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)
    })
    js
    data() {
      return {
        numbers: [1, 2, 3, 4, 5]
      }
    },
    computed: {
      evenNumbers() {
        return this.numbers.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)
    }
    js
    data() {
      return {
        sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
      }
    },
    methods: {
      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()
    Interpretação de Lista has loaded