1. 程式人生 > >Vue中key的作用

Vue中key的作用

# Vue中key的作用 `key`的特殊`attribute`主要用在`Vue`的虛擬`DOM`演算法,在新舊`Nodes`對比時辨識`VNodes`。如果不使用`key`,`Vue`會使用一種最大限度減少動態元素並且儘可能的嘗試就地修改、複用相同型別元素的演算法,而使用`key`時,它會基於`key`的變化重新排列元素順序,並且會移除`key`不存在的元素。此外有相同父元素的子元素必須有獨特的`key`,重複的`key`會造成渲染錯誤。 ## 描述 首先是官方文件的描述,當`Vue`正在更新使用`v-for`渲染的元素列表時,它預設使用就地更新的策略,如果資料項的順序被改變,`Vue`將不會移動`DOM`元素來匹配資料項的順序,而是就地更新每個元素,並且確保它們在每個索引位置正確渲染。這個預設的模式是高效的,但是隻適用於不依賴子元件狀態或臨時`DOM`狀態的列表渲染輸出,例如表單輸入值。為了給`Vue`一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 `key attribute`,建議儘可能在使用`v-for`時提供`key attribute`,除非遍歷輸出的`DOM`內容非常簡單,或者是刻意依賴預設行為以獲取效能上的提升。 簡單來說,當在列表迴圈中使用`key`時,需要使用`key`來給每個節點做一個唯一標識,`diff`演算法就可以正確的識別此節點,找到正確的位置直接操作節點,儘可能地進行重用元素,`key`的作用主要是為了高效的更新虛擬`DOM`。此外,使用`index`作為`key`是並不推薦的做法,其只能保證`Vue`在資料變化時強制更新元件,以避免原地複用帶來的副作用,但不能保證最大限度的元素重用,且使用`index`作為`key`在資料更新方面和不使用`key`的效果基本相同。 ## 示例 首先定義一個`Vue`例項,渲染四個列表,分別為簡單列表與複雜列表,以及其分別攜帶`key`與不攜帶`key`時對比其更新渲染時的速度,本次測試使用的是`Chrome 81.0`,每次在`Console`執行程式碼時首先會進行重新整理重新載入介面,避免瀏覽器以及`Vue`自身優化帶來的影響。 ```html Vue
  • {{item}}
  • {{item}}
  • 5">{{value}}
  • 5">{{value}}
``` ### 簡單列表 在簡單列表的情況下,不使用`key`可能會比使用`key`的情況下在更新時的渲染速度更快,這也就是官方文件中提到的,除非遍歷輸出的`DOM`內容非常簡單,或者是刻意依賴預設行為以獲取效能上的提升。在下面的例子中可以看到沒有`key`的情況下列表更新時渲染速度會快,當不存在`key`的情況下,這個列表直接進行原地複用,原有的節點的位置不變,原地複用元素,將內容更新為`5`、`6`、`7`、`8`、`9`、`10`,並添加了`11`與`12`兩個節點,而存在`key`的情況下,原有的`1`、`2`、`3`、`4`節點被刪除,`5`、`6`節點保留,添加了`7`、`8`、`9`、`10`、`11`、`12`六個節點,由於在`DOM`的增刪操作上比較耗時,所以表現為不帶`key`的情況下速度更快一些。 ```javascript // 沒有key的情況下 console.time(); vm.simpleListWithoutKey = [5, 6, 7, 8, 9, 10, 11, 12]; vm.$nextTick(() =>
console.timeEnd()); // default: 2.193056640625ms ``` ```javascript // 存在key的情況下 console.time(); vm.simpleListWithKey = [5, 6, 7, 8, 9, 10, 11, 12]; vm.$nextTick(() => console.timeEnd()); // default: 3.2138671875ms ``` 原地複用可能會帶來一些副作用,文件中提到原地複用這個預設的模式是高效的,但是隻適用於不依賴子元件狀態或臨時`DOM`狀態的列表渲染輸出,例如表單輸入值。在不設定`key`的情況下,元素中沒有與資料`data`繫結的部分,`Vue`會預設使用已經渲染的`DOM`,而綁定了資料`data`的部分會進行跟隨資料渲染,假如操作了元素位置,則元素中未繫結`data`的部分會停留在原地,而綁定了`data`的部分會跟隨操作進行移動,在下面的例子中首先需要將兩個`A`之後的輸入框新增資料資訊,這樣就製作了一個臨時狀態,如果此時點選下移按鈕,那麼不使用`key`的組中的輸入框將不會跟隨下移,且`B`到了頂端併成為了紅色,而使用`key`的組中會將輸入框進行下移,且`A`依舊是紅色跟隨下移。 ```html 就地複用

採用就地複用策略(vuejs預設情況)

{{p.name}}

不採用就地複用策略(設定key)

{{p.name}} ``` ### 複雜列表 使用`key`不僅能夠避免上述的原地複用的副作用,且在一些操作上可能能夠提高渲染的效率,主要體現在重新排序的情況,包括在中間插入和刪除節點的操作,在下面的例子中沒有`key`的情況下重新排序會原地複用元素,但是由於`v-if`綁定了`data`所以會一併進行操作,在這個`DOM`操作上比較消耗時間,而使用`key`得情況則直接複用元素,`v-if`控制的元素在初次渲染就已經決定,在本例中沒有對其進行更新,所以不涉及`v-if`的`DOM`操作,所以在效率上會高一些。 ```javascript console.time(); vm.complexListWithoutKey = [ {id: 3, list: [7, 8, 9]}, {id: 2, list: [4, 5, 6]}, {id: 1, list: [1, 2, 3]}, ]; vm.$nextTick(() =>
console.timeEnd()); vm.$nextTick(() => console.timeEnd()); // default: 4.100244140625ms ``` ```javascript console.time(); vm.complexListWithKey = [ {id: 3, list: [7, 8, 9]}, {id: 2, list: [4, 5, 6]}, {id: 1, list: [1, 2, 3]}, ]; vm.$nextTick(() => console.timeEnd()); // default: 3.016064453125ms ``` ## 每日一題 ``` https://github.com/WindrunnerMax/EveryDay ``` ## 參考 ``` https://cn.vuejs.org/v2/api/#key https://www.jianshu.com/p/4bdd2690859c https://www.zhihu.com/question/61078310 https://segmentfault.com/a/1190000012861862 https://www.cnblogs.com/zhumingzhenhao/p/7688336.html https://blog.csdn.net/hl18730262380/article/details/89306500 https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/1 https://cn.vuejs.org/v2/guide/list.html#%E7%BB%B4%E6%8A%A4%E7%8A%B6%E6%80