vue中key使用的問題示例解析
前言
在vue要求在遍歷的時候最好加上key,在使用過程中總有些疑問,在這里做下分析
不使用key的時候vue是怎么處理的
在vue2.x文檔中有如下描述
key 的特殊 attribute 主要用在 Vue 的虛擬 DOM 算法,在新舊 nodes 對比時辨識 VNodes。如果不使用 key,Vue 會使用一種最大限度減少動態(tài)元素并且盡可能的嘗試就地修改/復用相同類型元素的算法。而使用 key 時,它會基于 key 的變化重新排列元素順序,并且會移除 key 不存在的元素。
在這段話中提到不使用key的時候,會盡量原地復用,復用的判斷依據(jù)是常常在面試中被問到的sameVnode這個方法:
function sameVnode (a, b) {
return (
// 因為沒有定義key,可以得知a.key和b.key都是undefined,進而后面的條件進行判斷;
a.key === b.key && (
(
a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b)
) || (
isTrue(a.isAsyncPlaceholder) &&
a.asyncFactory === b.asyncFactory &&
isUndef(b.asyncFactory.error)
)
)
)
}
使用key一定能提高diff效率么
答案是并不是,可以看下面的例子
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
<div id="app">
<div class="ttt" v-for="(item) in list">{{item}}</div>
<button @click="changeData">更新</button>
</div>
<script >
new Vue({
el: '#app',
data() {
return {
list: [1, 2, 3]
}
},
mounted(){
Array.from(document.querySelectorAll('.ttt')).forEach(item=>{
item.dataset.mm = item.textContent;
})
},
methods:{
changeData(){
this.list = [4, 5, 6]
}
}
})
</script>
初始dom結構如下:

沒有key情況下更新數(shù)組,然后DOM結構如下,可以看到dataset值沒有變化,可以初步判斷只是更新了div的內(nèi)容

使用數(shù)組元素作為key情況下更新數(shù)組,然后DOM結構如下,可以看到dataset沒有了,可以初步判斷刪除和創(chuàng)建了新的dom,很明顯這樣處理效率更低。

vue源碼中的處理程序邏輯:
沒有key的情況: updateChildren -> 判定為同類型節(jié)點(div),執(zhí)行patchVnode方法 -> 再對div這個節(jié)點做updateChildren處理 -> 繼續(xù)patchVnode,最后的結果就是更新文本節(jié)點內(nèi)容;
if (oldVnode.text !== vnode.text) {
nodeOps.setTextContent(elm, vnode.text)
}
有key并且key不相等: updateChildren -> key不同,判定不同類型節(jié)點(div),執(zhí)行createElm方法,進而創(chuàng)建新的dom節(jié)點;
為什么說使用index作為key容易出錯
- 復現(xiàn)步驟:在第一行的Input里輸入1,在第二行Input里輸入2,然后點第一行的“ד刪除第一行
- 期待結果:刪除第一行后,應該變成“dog:2”
- 實際結果:刪除第一行后,變成了“dog:1”
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="index">
<test-row :name="item"></test-row>
<span style="color: red;cursor: pointer" @click="handleRemove(index)">X</span>
</li>
</ul>
</div>
<script>
Vue.component('test-row', {
template: `<span>
<span>{{ name }}:</span>
<input v-model="nums"/>
</span>`,
props: {
name: String
},
data() {
return {
nums: ''
}
}
})
new Vue({
el: '#app',
data() {
return {
list: ['cat', 'dog']
}
},
methods: {
handleRemove(i) {
this.list.splice(i, 1);
}
}
})
</script>
出現(xiàn)問題的原因:在patch階段會認為這兩個input子節(jié)點是sameVnode,進而復用原來的dom節(jié)點,因為組件只觸發(fā)了更新,沒有重新創(chuàng)建實例, 所以組件實例data數(shù)據(jù)沒有變化,輸入框內(nèi)的內(nèi)容就不會變化。
如果使用dog、cat作為key就可以避免這個bug;
以上就是vue中key使用的問題示例解析的詳細內(nèi)容,更多關于vue key使用問題的資料請關注腳本之家其它相關文章!
相關文章
vue-cli創(chuàng)建的項目,配置多頁面的實現(xiàn)方法
下面小編就為大家分享一篇vue-cli創(chuàng)建的項目,配置多頁面的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03
vue router動態(tài)路由設置參數(shù)可選問題
這篇文章主要介紹了vue-router動態(tài)路由設置參數(shù)可選,文中給大家提到了vue-router 動態(tài)添加 路由的方法,需要的朋友可以參考下2019-08-08
vite+vue3+element-plus搭建項目的踩坑記錄
這篇文章主要介紹了vite+vue3+element-plus搭建項目的踩坑記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
vue-element-admin 全局loading加載等待
本文主要介紹了vue-element-admin 全局loading加載等待,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
vue使用js-file-download插件下載文件亂碼的解決
這篇文章主要介紹了vue使用js-file-download插件下載文件亂碼的解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
uniapp 小程序和app map地圖上顯示多個酷炫動態(tài)的標點效果(頭像后端傳過來)
這篇文章主要介紹了uniapp 小程序和app map地圖上顯示多個酷炫動態(tài)的標點效果(頭像后端傳過來),本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09

