diff算法总结
1、为什么节点要加上key:key是这个节点的唯一标识,告诉diff算法,更改前后,他们是同一个dom节点。
2、只有同一个虚拟节点,才会进行diff算法(选择器相同,key相同),否则就会暴力删除旧的,插入新的
3、diff算法只进行同层比较,不会跨层比较,即使是用了同一片虚拟节点,但是跨层了,对不起,精细化不diff你,而是暴力删除旧的,插入新的
下面新建index.js来测试上面的三种情况,
1、为什么节点要加上key
// index.html中新增一个button按钮,一会来测试更改dom后,diff算法如何精细化比较
// <button id="btn">点击改变dom</button>
import {
init,
classModule,
propsModule,
styleModule,
eventListenersModule,
h,
} from "snabbdom";
//创建出patch函数(diff算法的核心函数),patch函数可以服务与让虚拟节点上树
const patch = init([init, classModule, propsModule, styleModule, eventListenersModule])
const container = document.getElementById('container')
const btn = document.getElementById('btn')
// 示例一:
const vnode1 = h('ul',{},[
h('li',{ key:'A' },'A'),
h('li',{ key:'B' },'B'),
h('li',{ key:'C' },'C'),
h('li',{ key:'D' },'D'),
])
const vnode2 = h('ul',{},[
h('li',{ key:'A' },'A'),
h('li',{ key:'B' },'B'),
h('li',{ key:'C' },'C'),
h('li',{ key:'D' },'D'),
h('li',{ key:'E' },'btn点击后:新增的E'),
])
// 渲染节点,请看下图1,
patch(container, vnode1)
// 点击按钮 将 vnode1 变为 vnode2,
// 为了更好理解diff算法,这里我们手动将节点A文字更改一下,
// 当按钮触发后,会发现,只是新增了E,而之前的节点没有改变,说名,diff算法只是做了精细化比较。
// 请看下图2
btn.onclick = function(){
patch(vnode1, vnode2)
}
2、只有同一个虚拟节点,才会进行diff算法(选择器相同,key相同),否则就会暴力删除旧的,插入新的
// 示例二:
// 注意:我们把父节点ul换成了ol,这个时候选择器不相同,diff就会暴力删除vnode3 ,插入vnode4
// 为了更好的理解,在html中我们直接把文字修改了,看下是不是会直接删除vnode3 ,查看图3,图4
// 查看图4可知,因为父节点不同,diff算法直接删除了旧的,插入新的。
const vnode3 = h('ul',{},[
h('li',{ key:'A' },'A'),
h('li',{ key:'B' },'B'),
h('li',{ key:'C' },'C'),
h('li',{ key:'D' },'D'),
])
const vnode4 = h('ol',{},[
h('li',{ key:'A' },'A'),
h('li',{ key:'B' },'B'),
h('li',{ key:'C' },'C'),
h('li',{ key:'D' },'D'),
])
patch(container, vnode3)
btn.onclick = function(){
patch(vnode3, vnode4)
}
3、diff算法只进行同层比较,不会跨层比较,即使是用了同一片虚拟节点,但是跨层了,对不起,精细化不diff你,而是暴力删除旧的,插入新的
// 示例三:
// vnode6多了一层section标签,这里不会进行diff。直接删除旧的,插入新的
// 查看图5,图6
const vnode5 = h('div',{},[
h('p',{ key:'A' },'A'),
h('p',{ key:'B' },'B'),
h('p',{ key:'C' },'C'),
h('p',{ key:'D' },'D'),
])
const vnode6 = h('div',{},h('section',{},[
h('p',{ key:'A' },'A'),
h('p',{ key:'B' },'B'),
h('p',{ key:'C' },'C'),
h('p',{ key:'D' },'D'),
]))
patch(container, vnode5)
btn.onclick = function(){
patch(vnode5, vnode6)
}