在使用 v-for 時有一些要注意的小地方,事先搞清楚這些觀念,在開發時就不會卡關哩。
陣列與物件使用 v-for 的索引不同
v-for 使用在陣列與物件上,索引會有什麼差別呢?
- 使用於陣列上 → 索引 (key) 為 0, 1, 2
<li v-for="(item, key) in arrayData">
{{ key }} - {{ item.name }} {{ item.age }} 歲
</li>
- 使用於物件上 → 索引 (key) 為物件的「屬性」
<li v-for="(item, key) in objectData">
{{ key }} - {{ item.name }} {{ item.age }} 歲
</li>
就地更新(快速置換)
如果我們在 <input>
上按照順序輸入 1 2 3
,接著按下按鈕反轉陣列,會發現 1 2 3
的順序沒有改變,這是為什麼呢?
<li v-for="(item, index) in arrayData">
{{ index }} - {{ item.name }} {{ item.age }} 歲
<input type="text" />
</li>
<button class="btn" @click="reverseArray">反轉陣列</button>
// methods 裡的 reverseArray
reverseArray: function () {
this.arrayData.reverse();
console.log(this.arrayData);
},
原因是因為 Vue 替換 DOM 元素是使用就地更新(快速置換)的方式。當 Vue 正在更新使用 v-for
渲染的元素列表時,它默認會使用「就地更新」的策略。
在就地更新的狀況下,資料的順序被改變時 Vue 不會因應資料順序而移動 DOM 元素,而是會就地更新每個元素的內容,並且確保它們在每個索引位置上正確渲染。
如果不想要就地更新,而希望要達到反轉,那我們需要給 Vue 提示,讓它能追蹤每個節點的身份,在重複使用的同時也正確地重新排序元素,而這個提示就是為每一項元素加上唯一的 key 值。
加上理想的 key 值
- 使用
:key
是為了避免就地複用(快速替換),因為我們想要強制替換 - 理想的 key 值是每個項目都有的唯一值,重複值不能當作 key
在這個例子中,使用 item.age
與 item.name
作為 key 都是可以的,但是不能用 :key = "index"
。
為什麼不行?這邊 index 不是剛好分別是 0, 1, 2 嗎?
這是因為如果用 index 當作唯一值,則在反轉前與反轉後,這些 index 在順序上依然都是 0, 1, 2,而不會變成 2, 1, 0,結果就會變成就地更新的情況了。
所以撰寫 key 的時候,如果有唯一值可以使用,就盡量不要使用 index 這種索引值。
使用 Filter 過濾或產出新內容
使用 v-for
的時候,常常會同時做過濾的行為,亦或是藉此產出想要的資料格式。
例如:將輸入的文字 (filterText) 過濾成畫面想要的內容 (filterArray)。
<input type="text" v-model="filterText" @keyup.enter="filterData" />
<ul>
<li v-for="(item, key) in filterArray" :key="item.age">
{{ key }} - {{ item.name }} {{ item.age }} 歲 <input type="text" />
</li>
</ul>
// methods 裡的 filterData
filterData: function () {
var vm = this; // 這個 this 指向 Vue 應用程式
vm.filterArray = vm.arrayData.filter(function (item) {
console.log(vm.filterText, item.name, item.name.match(vm.filterText));
return item.name.match(vm.filterText);
});
},
避免直接操作陣列內容
在 Vue.js 中直接指定陣列並修改資料,雖然這在 console 與 Vue 開發者工具中可以看到更改,但是畫面資料不會跟著變動。
// methods 裡的 cantWork
cantWork: function () {
this.arrayData[0] = {
name: '小強',
age: 99,
}
console.log(this.arrayData);
}
如果要操作陣列裡的內容,不能就這樣透過索引去操作,我們必須使用 Vue.set 去執行。
Vue.set(target, key, value)
想要操作或新增原本沒有在 data
裡的資料時,需要使用 Vue.set(針對目標, 索引, 值)
強制將資料寫入 data。
// methods 裡的 cantWork
cantWork: function () {
Vue.set(this.arrayData, 0, {
name: '阿強',
age: 99
});
console.log(this.arrayData);
}
純數字的迴圈
除了使用陣列或物件,也可以使用純數字的迴圈。
<ul>
<li v-for="item in 10">{{ item }}</li>
</ul>
使用 v-for="item in 一個數值"
,數值是多少,迴圈就會跑幾次。
在 Template 上使用 v-for
如果需要同時使用 v-for
與 v-if
的話,可以藉由在 <template>
標籤上使用 v-for
,唯一值 key
綁定在內部元素上的方式。
注意!雖然在官方文件的範例 v-for on a template 當中並沒有綁定 key
,但我認為還是應該加上 key
,目的是讓 Vue 在演算上能夠區分出元素的唯一性,因此我一樣會做綁定 key
的動作。
<ul>
<template v-for="item in items">
<li :key="item.uid" v-if="true">{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
以上資源是我自己整理過後的筆記,若有錯誤歡迎隨時和我聯繫