承上篇,談到 v-for
,就要說說它的最佳良伴——key
。
v-for
必須綁定代表唯一值的 key
若未綁定 key
值,Terminal 會直接報錯,表示「require 'v-bind:key'」,否則無法繼續編輯。
若 key
值出現重複的情況,DevTools 也會報錯。
key
值必須是字串或數字型別個人習慣一律準備 id
來綁定 key
值,但若是遍歷的資料結構較為簡單,且不會經過複雜的處理機制時,視情況可直接利用陣列的 index
作為替代。
<b-navbar-nav
class="my_navbar_item"
v-for="(navItem, navIndex) in navList"
:key="navIndex"
>
<b-nav-item href="#">{{ navItem.item }}</b-nav-item>
</b-navbar-nav>
也可以從 navList
陣列中的物件取得 item
內容來使用。
<b-navbar-nav
class="my_navbar_item"
v-for="navItem in navList"
:key="navItem.item"
>
<b-nav-item href="#">{{ navItem.item }}</b-nav-item>
</b-navbar-nav>
key
值:「id
」 VS 「index
」部分情況下若為求方便直接將 index
設為 key
值可能就會產生問題。
以下用一個包含 5 筆資料的簡單列表 list 作為範例,並增加下拉選單一起測試看看,打開 Vue.js Devtools 觀察 key
值綁定 id
和 index
的差別。
測試方式:先將下拉選單選定在第 4 筆資料,接著用 Vue.js Devtools 選取工具(Select)取得陣列資料後,再刪除第 3 筆資料。
<div v-for="(item, index) in list" :key="index">
index {{ index }} —— id {{ item.id }} —— {{ item.name }}
</div>
data() {
return {
select: "",
list: [
{ id: 1, name: "資料1" },
{ id: 2, name: "資料2" },
{ id: 3, name: "資料3" },
{ id: 4, name: "資料4" },
{ id: 5, name: "資料5" },
],
};
},
key
值綁定 index
<p>key: select index {{ select }}</p>
<select v-model="select">
<option v-for="(item, index) in list" :key="index" :value="index">
{{ item.name }}
</option>
</select>
選定第 4 筆資料,其 index
為 3。
刪除第 3 筆資料之後,index
3 變成對應到第 5 筆資料,造成選定項目跟著變動。
key
值綁定 id
<p>key: select id {{ select }}</p>
<select v-model="select">
<option v-for="item in list" :key="item.id" :value="item.id">
{{ item.name }}
</option>
</select>
選定第 4 筆資料,其 id
為 4。
刪除第 3 筆資料之後,因為 id
值並未受到影響,因此選取項目仍為原本選定的第 4 筆資料。
由於 Vue 採用「就地更新」策略,會以重複使用原本元件為原則來達到效能的提升,因此當資料被更新時(例如陣列資料改變排序),Vue 並不會大幅移動 DOM 元素來調整資料的順序,而是就地更新部分被改變的資料而已,所以需要透過綁定一個可作為唯一識別的 key
值,以確保資料能被有效複用及重新排序既有的元素。
經過上述測試我們可以理出結論:
id
具有唯一性,能直接對應到所屬項目,因此當陣列內容發生變動時,只需要處理增減的資料即可,其他資料仍可繼續複用,不需要重新渲染,進而維持效能。index
會跟著陣列內容的長度變化而隨之增減,且 index
具有順序性,所以只要變動其中一筆資料便會連帶影響到其他資料的排序,使得資料必須隨時重新渲染,相對影響效能。