原因:
Vue 和 React 都是采用diff算法來(lái)對(duì)比新舊虛擬dom節(jié)點(diǎn)去更新節(jié)點(diǎn)的吴侦。
在 Vue 的 diff 函數(shù)交叉對(duì)比中浴井,當(dāng)新節(jié)點(diǎn)和舊節(jié)點(diǎn)交叉對(duì)比沒有結(jié)果時(shí)音羞,會(huì)根據(jù)新節(jié)點(diǎn)的 key 去對(duì)比舊節(jié)點(diǎn)數(shù)組中的 key鞭执,從而找到相對(duì)應(yīng)的節(jié)點(diǎn)膛檀,如果沒有找到就認(rèn)為是一個(gè)新增節(jié)點(diǎn),而如果沒有 key斟赚,就會(huì)采用遍歷方式去查找對(duì)應(yīng)的舊節(jié)點(diǎn)着降。
當(dāng) Vue 正在更新使用 v-for 渲染的元素列表時(shí),它默認(rèn)使用“就地復(fù)用”的策略拗军。如果數(shù)據(jù)項(xiàng)的順序被改變任洞,Vue 將不會(huì)移動(dòng) DOM 元素來(lái)匹配數(shù)據(jù)項(xiàng)的順序蓄喇,而是簡(jiǎn)單復(fù)用此處每個(gè)元素。并且確保它們?cè)诿總€(gè)索引位置正確渲染交掏。這個(gè)默認(rèn)的模式是高效的妆偏,但是只適用于不依賴子組件狀態(tài)或臨時(shí)DOM狀態(tài)(例如:表單輸入值)的列表渲染輸出。在沒有綁定key 且遍歷模板簡(jiǎn)單的情況下盅弛,會(huì)導(dǎo)致新舊虛擬節(jié)點(diǎn)對(duì)比高效钱骂,節(jié)點(diǎn)也會(huì)復(fù)用,而這種復(fù)用就是“就地復(fù)用”挪鹏。
作用:
1.避免對(duì)節(jié)點(diǎn)“就地復(fù)用”见秽。需要修改的節(jié)點(diǎn)位置沒有變,是內(nèi)容更新了讨盒,這雖然提高了復(fù)用性能解取,但是往往在復(fù)雜的表單中會(huì)導(dǎo)致狀態(tài)出現(xiàn)錯(cuò)位,也不會(huì)產(chǎn)生過渡效果催植。帶有 key 就不會(huì)使用“就地復(fù)用”了肮蛹,在 sameNode 函數(shù) a.key===b.key 對(duì)比中就可以避免“就地復(fù)用”的情況。
2.在有 key 的情況下增加準(zhǔn)確性创南,key 相當(dāng)于每個(gè) Vnode 的唯一 id伦忠,我們可以依靠 key,更快更精確的知道 oIdVnode中 對(duì)應(yīng)的 Vnode 節(jié)點(diǎn)稿辙。利用 key 的唯一性生成 map 對(duì)象來(lái)獲取相對(duì)應(yīng)的節(jié)點(diǎn)昆码,比遍歷方式更快。
“就地復(fù)用”的解釋:
如果數(shù)據(jù)項(xiàng)的順序被改變邻储,Vue 將不會(huì)移動(dòng) DOM 元素來(lái)匹配數(shù)據(jù)項(xiàng)的順序赋咽,而是簡(jiǎn)單復(fù)用此處每個(gè)元素。
這句話比較難理解吨娜,看下邊這個(gè)例子:
首先文本脓匿,輸入框,按鈕是寫在一個(gè) div 里面宦赠。
在“就地復(fù)用”策略中陪毡,點(diǎn)擊按鈕,輸入框不隨文本一起下移勾扭,是因?yàn)檩斎肟驔]有與數(shù)據(jù)(data)綁定毡琉,所以 vuejs默認(rèn)使用已經(jīng)渲染的 DOM,然而文本與數(shù)據(jù)是綁定的,所以文本被重新渲染妙色,這種處理方式在 Vue 或者 Angularjs都是默認(rèn)的列表渲染策略桅滋,因?yàn)楦咝А?/p>
這種“就地復(fù)用”一般在“列表展示”的場(chǎng)景中不會(huì)出現(xiàn)問題,所以我的建議是:如果你的列表元素存在與用戶交互的場(chǎng)景(比如form表單或者重新排序等)身辨,那么請(qǐng)你為 v-for 指令設(shè)置 key 參數(shù)丐谋,key 指向列表中每個(gè)元素的唯一值芍碧。
官方解釋:
“就地復(fù)用”的模式是高效的,但是只適用于不依賴子組件狀態(tài)或臨時(shí) DOM 狀態(tài)(例如:表單輸入值)的列表渲染輸出号俐。