v-for中key的作用與原理

2022-11-04 12:00:27

一、虛擬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。

四、總結

  1. 用index作為key可能會引發的問題:若對資料進行逆序新增、逆序刪除等破壞順序的操作時,會產生沒有必要的真實DOM更新,此時介面效果沒有問題,但效率太低。
  2. 在開發中如何選擇key:最好使用每條資料的唯一標識作為key,比如id、身份證號、手機號等,如果不存在對資料的逆序新增、逆序刪除等破壞順序操作,僅用於渲染列表用於展示,使用index作為key是沒有問題的。