上一篇《虚拟 DOM 和 diff 算法 -01》我们手写实现了 h 函数,本篇着重介绍 diff 算法。
diff 算法的特点
- 如果是往数组的最后面添加节点,那么前面的节点不会改动
比如有如下新(vnode2)旧(vnode1)两个节点,那么执行 patch(vnode1, vnode2)
会发现仅仅浏览器只是追加了一个节点 <div>东风破</div>
, 不会改变前两个。
可以通过在浏览器调试工具里直接将“七里香”改成“七里不香”,然后通过点击按钮执行 patch(vnode1, vnode2) 会发现“七里不香”依旧没变。
- key 很重要,key 作为节点的标识,告诉 diff 算法在更改前后节点是否为同一个
如果是往数组的开头添加节点,则所有的节点都会被改动,想要做到最小化更新,需要给每个节点添加 key 属性,这样 <div>七里香</div>
和 <div>东风破</div>
两个节点就不会被改动了
- 只有是同一个虚拟节点,才进行精细化比较,否则直接删除旧节点,插入新节点
判断两个节点是否为同一个,是根据比较选择器,也就是 sel 的值和 key 的值是否都相同,都相等则判断为同一个虚拟节点
- 只进行同层比较
新旧节点的层级要相同,比如下面的例子里新节点比旧节点多了层 div,则不会进行精细化比较,直接删除旧节点插入新节点
手写 patch 函数
diff 算法是通过 patch 函数实现的,在开始手写之前,我们先来理清 patch 函数做了什么
函数功能分析
可以通过之前下载到 node_modules 里的 snabbdom 查看源码,patch 函数被定义在了 snabbdom 下的 src 目录下的 init.ts 里
根据源码得到如下流程图
手写第一次上树
新建 patch.js 文件,引入 vnode 函数用于将非虚拟节点的 oldVnode 包装为虚拟节点
新建 creatElement.js 并在 patch.js 引入 creatElement 函数,用于创建新节点,并将对应的虚拟节点的 elm 属性赋值为创建出的新节点
至此,我们已经完成了上面 patch 函数流程图中除了“精细化比较”之外的内容。接下来就开始着手当 oldVnode 和 newVnode 是同一节点的情况下的精细化比较的内容,这部分将有较多的图示,写在本篇难免会导致页面过长,我将在下篇继续分享~
One More Thing
本文有用到一些插入节点的方法,现在就此做一个扩展总结
- innerHTML(属性):获取标签内部的HTML内容
- outerHTML(属性):获取包括目标标签在内,以及内部HTML的内容
- appendChild(函数):向目标标签末尾添加子节点,返回参数节点
- insertBefore(函数):向目标节点的第二个参数位置添加第一个参数为子节点,返回第一个参数
- insertAdjacentHTML(函数):向目标节点的指定位置添加节点
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!