Vue 3.0 列表渲染

2021-07-16 11:28 更新

#v-for 把一個數(shù)組對應(yīng)為一組元素

我們可以用 v-for 指令基于一個數(shù)組來渲染一個列表。v-for 指令需要使用 item in items 形式的特殊語法,其中 items 是源數(shù)據(jù)數(shù)組,而 item 則是被迭代的數(shù)組元素的別名

<ul id="array-rendering">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>

Vue.createApp({
  data() {
    return {
      items: [{ message: 'Foo' }, { message: 'Bar' }]
    }
  }
}).mount('#array-rendering')

結(jié)果: 點(diǎn)擊此處實現(xiàn)

v-for 塊中,我們可以訪問所有父作用域的 property。v-for 還支持一個可選的第二個參數(shù),即當(dāng)前項的索引。

<ul id="array-with-index">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>

Vue.createApp({
  data() {
    return {
      parentMessage: 'Parent',
      items: [{ message: 'Foo' }, { message: 'Bar' }]
    }
  }
}).mount('#array-with-index')

結(jié)果: 點(diǎn)擊此處實現(xiàn)

你也可以用 of 替代 in 作為分隔符,因為它更接近 JavaScript 迭代器的語法:

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

#v-for 里使用對象

你也可以用 v-for 來遍歷一個對象的 property。

<ul id="v-for-object" class="demo">
  <li v-for="value in myObject">
    {{ value }}
  </li>
</ul>

Vue.createApp({
  data() {
    return {
      myObject: {
        title: 'How to do lists in Vue',
        author: 'Jane Doe',
        publishedAt: '2016-04-10'
      }
    }
  }
}).mount('#v-for-object')

結(jié)果: 點(diǎn)擊此處實現(xiàn)

你也可以提供第二個的參數(shù)為 property 名稱 (也就是鍵名 key):

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

點(diǎn)擊此處實現(xiàn)

還可以用第三個參數(shù)作為索引:

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

點(diǎn)擊此處實現(xiàn)

提示

在遍歷對象時,會按 Object.keys() 的結(jié)果遍歷,但是不能保證它在不同 JavaScript 引擎下的結(jié)果都一致。

#維護(hù)狀態(tài)

當(dāng) Vue 正在更新使用 v-for 渲染的元素列表時,它默認(rèn)使用“就地更新”的策略。如果數(shù)據(jù)項的順序被改變,Vue 將不會移動 DOM 元素來匹配數(shù)據(jù)項的順序,而是就地更新每個元素,并且確保它們在每個索引位置正確渲染。

這個默認(rèn)的模式是高效的,但是只適用于不依賴子組件狀態(tài)或臨時 DOM 狀態(tài) (例如:表單輸入值) 的列表渲染輸出。

為了給 Vue 一個提示,以便它能跟蹤每個節(jié)點(diǎn)的身份,從而重用和重新排序現(xiàn)有元素,你需要為每項提供一個唯一 key attribute:

<div v-for="item in items" :key="item.id">
  <!-- content -->
</div>

建議盡可能在使用 v-for 時提供 key attribute,除非遍歷輸出的 DOM 內(nèi)容非常簡單,或者是刻意依賴默認(rèn)行為以獲取性能上的提升。

因為它是 Vue 識別節(jié)點(diǎn)的一個通用機(jī)制,key 并不僅與 v-for 特別關(guān)聯(lián)。后面我們將在指南中看到,它還具有其它用途。

提示

不要使用對象或數(shù)組之類的非基本類型值作為 v-for 的 key。請用字符串或數(shù)值類型的值。

更多 key attribute 的細(xì)節(jié)用法請移步至 key 的 API 文檔。

#數(shù)組更新檢測

#變更方法

Vue 將被偵聽的數(shù)組的變更方法進(jìn)行了包裹,所以它們也將會觸發(fā)視圖更新。這些被包裹過的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

你可以打開控制臺,然后對前面例子的 items 數(shù)組嘗試調(diào)用變更方法。比如 example1.items.push({ message: 'Baz' })。

#替換數(shù)組

變更方法,顧名思義,會變更調(diào)用了這些方法的原始數(shù)組。相比之下,也有非變更方法,例如 filter()、concat()slice()。它們不會變更原始數(shù)組,而總是返回一個新數(shù)組。當(dāng)使用非變更方法時,可以用新數(shù)組替換舊數(shù)組:

example1.items = example1.items.filter(item => item.message.match(/Foo/))

你可能認(rèn)為這將導(dǎo)致 Vue 丟棄現(xiàn)有 DOM 并重新渲染整個列表。幸運(yùn)的是,事實并非如此。Vue 為了使得 DOM 元素得到最大范圍的重用而實現(xiàn)了一些智能的啟發(fā)式方法,所以用一個含有相同元素的數(shù)組去替換原來的數(shù)組是非常高效的操作。

#顯示過濾/排序后的結(jié)果

有時,我們想要顯示一個數(shù)組經(jīng)過過濾或排序后的版本,而不實際變更或重置原始數(shù)據(jù)。在這種情況下,可以創(chuàng)建一個計算屬性,來返回過濾或排序后的數(shù)組。

例如:

<li v-for="n in evenNumbers">{{ n }}</li>

data() {
  return {
    numbers: [ 1, 2, 3, 4, 5 ]
  }
},
computed: {
  evenNumbers() {
    return this.numbers.filter(number => number % 2 === 0)
  }
}

在計算屬性不適用的情況下 (例如,在嵌套 v-for 循環(huán)中) 你可以使用一個方法:

<ul v-for="numbers in sets">
  <li v-for="n in even(numbers)">{{ n }}</li>
</ul>

data() {
  return {
    sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
  }
},
methods: {
  even(numbers) {
    return numbers.filter(number => number % 2 === 0)
  }
}

#v-for 里使用值的范圍

v-for 也可以接受整數(shù)。在這種情況下,它會把模板重復(fù)對應(yīng)次數(shù)。

<div id="range" class="demo">
  <span v-for="n in 10">{{ n }} </span>
</div>

結(jié)果: 點(diǎn)擊此處實現(xiàn)

#<template> 中使用 v-for

類似于 v-if,你也可以利用帶有 v-for<template> 來循環(huán)渲染一段包含多個元素的內(nèi)容。比如:

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

#v-forv-if 一同使用

TIP

注意我們推薦在同一元素上使用 v-ifv-for。更多細(xì)節(jié)可查閱風(fēng)格指南。

當(dāng)它們處于同一節(jié)點(diǎn),v-if 的優(yōu)先級比 v-for 更高,這意味著 v-if 將沒有權(quán)限訪問 v-for 里的變量:

<!-- This will throw an error because property "todo" is not defined on instance. -->


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

可以把 v-for 移動到 <template> 標(biāo)簽中來修正:

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

#在組件上使用 v-for

這部分內(nèi)容假定你已經(jīng)了解組件相關(guān)知識。你也完全可以先跳過它,以后再回來查看。

在自定義組件上,你可以像在任何普通元素上一樣使用 v-for

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

然而,任何數(shù)據(jù)都不會被自動傳遞到組件里,因為組件有自己獨(dú)立的作用域。為了把迭代數(shù)據(jù)傳遞到組件里,我們要使用 props:

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

不自動將 item 注入到組件里的原因是,這會使得組件與 v-for 的運(yùn)作緊密耦合。明確組件數(shù)據(jù)的來源能夠使組件在其他場合重復(fù)使用。

下面是一個簡單的 todo 列表的完整例子:

<div id="todo-list-example">
  <form v-on:submit.prevent="addNewTodo">
    <label for="new-todo">Add a todo</label>
    <input
      v-model="newTodoText"
      id="new-todo"
      placeholder="E.g. Feed the cat"
    />
    <button>Add</button>
  </form>
  <ul>
    <todo-item
      v-for="(todo, index) in todos"
      :key="todo.id"
      :title="todo.title"
      @remove="todos.splice(index, 1)"
    ></todo-item>
  </ul>
</div>

const app = Vue.createApp({
  data() {
    return {
      newTodoText: '',
      todos: [
        {
          id: 1,
          title: 'Do the dishes'
        },
        {
          id: 2,
          title: 'Take out the trash'
        },
        {
          id: 3,
          title: 'Mow the lawn'
        }
      ],
      nextTodoId: 4
    }
  },
  methods: {
    addNewTodo() {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})


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


app.mount('#todo-list-example')

點(diǎn)擊此處實現(xiàn)

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號