key是虛擬DOM物件的標識,當資料發生變化時,Vue會根據新資料生成新的虛擬DOM,隨後Vue會對新虛擬DOM與舊虛擬DOM的差異進行比較。
最好使用每條資料的唯一標識作為key,用一個簡單的例子說明:
點選按鈕在列表最前方新增趙六使用者
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}
<input type="text">
</li>
<br>
<button @click="Add">在最前方新增一個使用者</button>
</ul>
data () {
return {
persons: [
{id: '01', name: '張三'},
{id: '02', name: '李四'},
{id: '03', name: '王五'}
]
}
},
methods: {
Add () {
let p = {id: '04', name: '趙六'}
this.persons.unshift(p)
}
}
點選以後,頁面如下圖
然而,如果在我點選按鈕前,在輸入框中輸入一些內容
點選按鈕後就會變成
很明顯,這並不是我們理想中想要呈現的效果。
<ul>
<li v-for="p of persons" :key="p.id">
{{p.name}}
<input type="text">
</li>
<br>
<button @click="Add">在最前方新增一個使用者</button>
</ul>
在輸入框中輸入與之前相同的內容,點選按鈕後這次的頁面則變成了下圖
很明顯,這次就對了!
為什麼用id和index作為key出來的效果天差地別呢,首先來分析一下key的作用原理。
首先會根據初始資料生成虛擬DOM,然後將虛擬DOM轉為真實DOM,在加入新資料以後,再根據新資料生成新的虛擬DOM,此時Vue並不會再重新將新虛擬DOM直接轉為真實DOM,而是進行一個虛擬DOM的對比演演算法。如下:
首先在新的虛擬DOM中按照順序取出第一項,然後根據標識「key=0」在舊的虛擬DOM中尋找擁有一樣「key=0」的節點,然後開始挨個對比。
第一個節點為文位元組點,Vue發現一個為張三一個為趙六,不一致,於是將新的文位元組點趙六轉為真實DOM
然後來到第二個標籤節點input,需要注意的是,我們對文字方塊的輸入是在真實DOM中操作的,但在虛擬DOM中兩邊的標籤節點input是一樣的,所以這時候Vue不會將它重新轉成真實DOM,而是直接複用左邊的。
以此類推,key等於1和等於2時,文位元組點重新轉為真實DOM,標籤節點複用。
當來到key等於3這一項時,發現左邊並沒有key是等於3的一項,所以這個時候,Vue直接將右邊key等於3這一項直接轉為真實DOM。
首先也是按照順序取出第一項,然後根據標識「key=04」在左邊尋找擁有同樣key的一項,發現沒有,於是直接轉為真實DOM。
然後按順序取出第二項,根據標識「key=01」,在左邊尋找也是「key=01」的一項,挨個對比文位元組點和標籤節點,發現兩個節點都完全一樣,所以直接複用之前的真實DOM。
以此類推,李四和王五都是直接複用左邊的真實DOM。