v-for中key的作用與原理
一、虛擬DOM中key的作用
key是虛擬DOM對象的標識,當數據發生變化時,Vue會根據新數據生成新的虛擬DOM,隨後Vue會對新虛擬DOM與舊虛擬DOM的差異進行比較。
二、如何選擇key
最好使用每條數據的唯一標識作為key,用一個簡單的例子說明:
1.用index作為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)
}
}
點擊以後,頁面如下圖
然而,如果在我點擊按鈕前,在輸入框中輸入一些內容
點擊按鈕後就會變成
很明顯,這並不是我們理想中想要呈現的效果。
2.用id作為key時
<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的作用原理。
用index作為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。
用id作為key時:
首先也是按照順序取出第一項,然後根據標識「key=04」在左邊尋找擁有同樣key的一項,發現沒有,於是直接轉為真實DOM。
然後按順序取出第二項,根據標識「key=01」,在左邊尋找也是「key=01」的一項,挨個對比文本節點和標籤節點,發現兩個節點都完全一樣,所以直接復用之前的真實DOM。
以此類推,李四和王五都是直接復用左邊的真實DOM。
四、總結
- 用index作為key可能會引發的問題:若對數據進行逆序添加、逆序刪除等破壞順序的操作時,會產生沒有必要的真實DOM更新,此時界面效果沒有問題,但效率太低。
- 在開發中如何選擇key:最好使用每條數據的唯一標識作為key,比如id、身份證號、手機號等,如果不存在對數據的逆序添加、逆序刪除等破壞順序操作,僅用於渲染列表用於展示,使用index作為key是沒有問題的。