更新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了