diff演算法是如何比較的,保證讓你看的明明白白的!
阿新 • • 發佈:2021-12-13
更新dom節點,最小力度去跟新
index.html <body> <h1>你好啊!</h1> <button id="btn">該變資料</button> <div id="container"></div> </body> <script src="xuni/bundle.js"></script> </html> index.js檔案 import { init, classModule, propsModule, styleModule, eventListenersModule, h, } from "snabbdom"; let myVnode1 = h('ul', {}, [ h('li', {}, '姓名'), h('li', {}, '年齡'), h('li', {}, '愛好'), ]) // 使用init函式建立 patch函式 const patch = init([classModule, propsModule, styleModule, eventListenersModule]) const container = document.getElementById('container') // 讓虛擬節點上樹 patch(container, myVnode1) // 改變資料 let myVnode2 = h('ul', {}, [ h('li', {}, '姓名'), h('li', {}, '年齡'), h('li', {}, '愛好'), h('li', {}, '性別'), ]) let btn = document.getElementById('btn') btn.onclick = function () { patch(myVnode1,myVnode2) }
發現的現象
當我手動去更改頁面中的資料的時候。
在點選按鈕。我們發現只追加了性別。
我更改的資料並沒有跟新。
說明diff是進行最小力度去跟新的
那我們把資料新增在最前面會發生什麼呢?
let myVnode1 = h('ul', {}, [ h('li', {}, '姓名'), h('li', {}, '年齡'), h('li', {}, '愛好'), ]) // 使用init函式建立 patch函式 const patch = init([classModule, propsModule, styleModule, eventListenersModule]) const container = document.getElementById('container') // 讓虛擬節點上樹 patch(container, myVnode1) // 改變資料 let myVnode2 = h('ul', {}, [ //在最前面新增,發現跟剛才的比一樣了? //他將我們更改的資料復原了? //這個時候又小夥伴會說,diff不是最小粒度去更新了 h('li', {}, '性別'), h('li', {}, '姓名'), h('li', {}, '年齡'), h('li', {}, '愛好'), ]) let btn = document.getElementById('btn') btn.onclick = function () { patch(myVnode1,myVnode2) }
diff不是最小粒度跟新?
在最前面新增,發現跟剛才的比一樣了?
他將我們更改的資料復原了?
這個時候又小夥伴會說,diff不是最小粒度去更新了?
其實diff一直都是最小力度跟新,是你忘記增加key值了。
我們加上key值看看呢??
新增key值後
let myVnode1 = h('ul', {}, [ h('li', {key:'001'}, '姓名'), h('li', {key:'002'}, '年齡'), h('li', {key:'003'}, '愛好'), ]) // 使用init函式建立 patch函式 const patch = init([classModule, propsModule, styleModule, eventListenersModule]) const container = document.getElementById('container') // 讓虛擬節點上樹 patch(container, myVnode1) // 改變資料 let myVnode2 = h('ul', {}, [ h('li', {key:'00x'}, '性別'), h('li', {key:'001'}, '姓名'), h('li', {key:'002'}, '年齡'), h('li', {key:'003'}, '愛好'), ]) let btn = document.getElementById('btn') btn.onclick = function () { patch(myVnode1,myVnode2) }
新增key值頂級節點型別改變的情況
當我們新增key值後,發現數據果然是最小力度去更新的,對吧!
如果將ul更改為div,還是最小力度跟新嗎?
let myVnode1 = h('ul', {}, [
h('li', {key:'001'}, '姓名'),
h('li', {key:'002'}, '年齡'),
h('li', {key:'003'}, '愛好'),
])
// 使用init函式建立 patch函式
const patch = init([classModule, propsModule, styleModule, eventListenersModule])
const container = document.getElementById('container')
// 讓虛擬節點上樹
patch(container, myVnode1)
// 改變資料
let myVnode2 = h('div', {}, [
h('li', {key:'001'}, '姓名'),
h('li', {key:'002'}, '年齡'),
h('li', {key:'003'}, '愛好'),
])
let btn = document.getElementById('btn')
btn.onclick = function () {
patch(myVnode1,myVnode2)
}
這個時候我們增加上key值了,按照之前的操作。
發現一個問題。資料全部恢復最初始值了。
在採取diff演算法比較:新舊節點進行比較,
比較只會在同層級進行, 不會跨層級比較。
如果兩個節點都是一樣的,那麼就深入檢查他們的子節點。
果兩個節點不一樣那就說明 Vnode 完全被改變了(ul和div節點不一樣),
就可以直接使用新節點替換老節點。【他們的子代不會進行比較了】
雖然這兩個節點不一樣但是他們的子節點一樣怎麼辦?
別忘了,diff可是逐層比較的,
如果[第一層不一樣那麼就不會繼續深入比較第二層了。
(我在想這算是一個缺點嗎?相同子節點不能重複利用了??...)
這個時候你可能會說:這個diff演算法也不會那麼牛逼呢!
並不是最優的。
【雖然這兩個節點不一樣但是他們的子節點一樣怎麼辦?】
在我們工作中:其實這指一種非常合理的機制。
我們幾乎並不會出現這樣的情況
<ul v-if="falg">
<li v-for="item,index" in list>{{item }}</li>
</ul>
<ol v-if="falg">
<li v-for="item,index" in list>{{item }}</li>
</ol>
這樣的程式碼在我們工作中幾乎是不會出現的呢?
什麼叫做不會跨層比較?
<div>
<p>123123 </p>
</div>
與
<div>
<h2> <p>123123 </p> </h2>
</div>
div與div比較
p與h2比較
當p與h2比較的時候,他們他們節點不一樣,直接使用替換。
此時並不會在使用diff了
作者:明月人倚樓 出處:https://www.cnblogs.com/IwishIcould/
想問問題,打賞了卑微的博主,求求你備註一下的扣扣或者微信;這樣我好聯絡你;(っ•̀ω•́)っ✎⁾⁾!
如果覺得這篇文章對你有小小的幫助的話,記得在右下角點個“推薦”哦,或者關注博主,在此感謝!
萬水千山總是情,打賞5毛買辣條行不行,所以如果你心情還比較高興,也是可以掃碼打賞博主(っ•̀ω•́)っ✎⁾⁾!
想問問題,打賞了卑微的博主,求求你備註一下的扣扣或者微信;這樣我好聯絡你;(っ•̀ω•́)っ✎⁾⁾!
支付寶 微信 本文版權歸作者所有,歡迎轉載,未經作者同意須保留此段宣告,在文章頁面明顯位置給出原文連線如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。