您好,登錄后才能下訂單哦!
這篇文章給大家介紹Vuejs中key值的作用是什么,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
index
作為 key
不知道你在寫 v-for
的時候,會不會直接使用 index
作為它的 key
值,是的,我承認我會,不得不說,這真的不是一個好習慣。
根據上篇文章,我們還是用 sortable.js
作為例子討論。以下是核心代碼,其中 arrData
的值為 [1,2,3,4]
<div id="sort"> <div v-for="(item,index) in arrData" :key="index" > <div>{{item}}</div> </div> </div>
mounted () { let el = document.getElementById('sort') var sortable = new Sortable(el, { onEnd: (e) => { const tempItem = this.arrData.splice(e.oldIndex, 1)[0] this.arrData.splice(e.newIndex, 0, tempItem) } }) }
當然一開始的時候,數據渲染肯定是沒有問題的
好了,我們來看下以下的操作:
可以看到,我將3拖到2上面的時候,下面的數據變成了 1342,但是上面視圖的還是1234。然后我第四位置拖到第三位置的時候,下面的數據也是生效的,但是上面的數據似乎全部錯亂了。很好,我們重現了案發現場。
接著我改了綁定的 key
值,因為這里的例子比較特殊,我們就認為 item
的值都不相同
<div id="sort"> <div v-for="(item,index) in arrData" :key="item" > <div>{{item}}</div> </div> </div>
再看效果:
是的,這個時候數據就完全跟視圖同步了。
為什么?
先看官方文檔中 key
的一句介紹
有相同父元素的子元素必須有獨特的 key。重復的 key 會造成渲染錯誤。
之所以會造成上面渲染錯誤的情況,是因為我們的 key
值不是獨特的,比如上面的 key
值,在調整數組順序后就每一項原來的 key
值都變了,所以導致了渲染錯誤。
我們先來得出一個結論,用 index
作為 key
值是有隱患的,除非你能保證 index
始終能夠能夠作為一個唯一的標識
在 vue2.0
之后,我們不寫 key
的話,就會報 warning
,那也就是說官方是希望我們寫 key
值的,那么 key
到底在 vue
中扮演了什么樣的角色?
不使用 key 可以提高性能么答案是,是的!可以!
先看官方解釋:
如果不使用 key,Vue 會使用一種最大限度減少動態元素并且盡可能的嘗試修復/再利用相同類型元素的算法。使用 key,它會基于 key 的變化重新排列元素順序,并且會移除 key 不存在的元素。
比如現在有一個數組 [1,2,3,4]變成了[2,1,3,4],那么沒有 key
的值會采取一種“就地更新策略”,見下圖。它不會移動元素節點的位置,而是直接修改元素本身,這樣就節省了一部分性能
而對于有 key
值的元素,它的更新方式如下圖所示。可以看到,這里它對 DOM 是移除/添加的操作,這是比較耗性能的。
竟然不帶 key
性能更優,為何還要帶 key先來看一個例子,核心代碼如下,這里模仿一個切換 tab
的功能,也就是切換的tab1 是1,2,3,4。tab2 是 5,6,7,8。其中有設置了一個點擊設置第一項字體色為紅色的功能。
那么當我們點擊tab1將字體色設置成紅色之后,再切換到 tab2,我們預期的結果是我們第一項字體的初始顏色而不是紅色,但是結果卻還是紅色。
<div id="sort"> <button @click="trunToTab1">tab1</button> <button @click="trunToTab2">tab2</button> <div v-for="(item, index) in arrData"> <div @click="clickItem(index)" class="item">{{item}}</div> </div> </div>
trunToTab1 () { this.arrData = [1,2,3,4] }, trunToTab2 () { this.arrData = [5,6,7,8] }, clickItem () { document.getElementsByClassName('item')[0].style.color = 'red' }
這就超出了我們的預期了,也就是官方文檔所說的,默認模式指的就是不帶 key
的狀態,對于依賴于子組件狀態或者臨時 DOM 狀態的,這種模式是不適用的。
這個默認的模式是高效的,但是只適用于不依賴子組件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。
我們來看帶上 key
之后的效果
這就是官方文檔之所以推薦我們寫 key
的原因,根據文檔的介紹,如下:
使用
key
,它會基于key
的變化重新排列元素順序,并且會移除key
不存在的元素。 它也可以用于強制替換元素/組件而不是重復使用它。當你遇到如下場景的時候它可能會很有用:
完整地觸發組件的生命周期鉤子
觸發過渡
那么 Vue
底層 key
值到底是怎么去做到以上的功能?我們就得聊聊 diff
算法以及虛擬 DOM
了。
這里我們不談 diff
算法的具體,只看 key
值在其中的作用。(diff
算法有機會我們再聊)
看 vue
源碼中 src/core/vdom/patch.js
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx) idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
我們整理一下代碼塊:
// 如果有帶 key if (isUndef(oldKeyToIdx)) { // 創建 index 表 oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); } if (isDef(newStartVnode.key)) { // 有 key ,直接從上面創建中獲取 idxInOld = oldKeyToIdx[newStartVnode.key] } else { // 沒有key, 調用 findIdxInOld idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx); }
那么最主要還是 createKeyToOldIdx
和 findIdxInOld
兩個函數的比較,那么他們做了什么呢?
function createKeyToOldIdx (children, beginIdx, endIdx) { let i, key const map = {} for (i = beginIdx; i <= endIdx; ++i) { key = children[i].key if (isDef(key)) map[key] = i } return map }
function findIdxInOld (node, oldCh, start, end) { for (let i = start; i < end; i++) { const c = oldCh[i] if (isDef(c) && sameVnode(node, c)) return i } }
我們可以看到,如果我們有 key
值,我們就可以直接在 createKeyToOldIdx
方法中創建的 map
對象中根據我們的 key
值,直接找到相應的值。沒有 key
值,則需要遍歷才能拿到。相比于遍歷,映射的速度會更快。
key
值是每一個 vnode
的唯一標識,依靠 key
,我們可以更快的拿到 oldVnode
中相對應的節點。
關于Vuejs中key值的作用是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。