这次 我们来讲 diff算法处理到 当新旧节点 是同一个节点时的处理
我们之前也说过 如果不是同一个节点 他就会暴力拆旧 把新的插上去
但当他们是同一个节点 需要精细化比较 最做小化更新 这块我们还没有处理
打开我们的案例 打开 patch.js
对应其实就还是这一块还没有写
我们先将 src下的index.js改成这样
import h from "./snabbdom/h";
import patch from "./snabbdom/patch";
const container = document.getElementById("container");
const vnode = h("ul", {}, [
h("li", {}, "1A"),
h("li", {}, "2B"),
h("li", {}, "3C")
]);
patch( container, vnode)
const btn = document.getElementById("btn");
const vnode1 = h("ul", {}, [
h("li", {}, "1A"),
h("li", {}, "2B"),
h("li", {}, "3C"),
h("li", {}, "4D")
]);
btn.onclick = function(){
patch( vnode, vnode1)
}
可以看到 我们设置 通过getElementById获取btn 按钮 给他添加事件 当点击是通过patch更换虚拟dom节点 而我们更新前和更新后 其实只相差一个li标签
多了一个4D
我们运行项目
然后 我们点击更改dom
你会发现 没有任何反应 应该 我们也看到了 刚才 patch.js 中 判断为同一节点之后 里面是空的 没有任何逻辑
其实这个地方复杂也还是比较复杂的 因为情况比较多
例如 可能是新节点是文本 老节点有子节点 或者 老节点有文本 新节点是子节点 或者 都是文本 都是子节点
这个都是要考虑进去的 我们看看原文
打开 node_modules/snabbdom/src/init.ts
看到最下面的patch
他确认为同一节点 会调用 patchVnode 我们按住Ctrl 点击进入这个函数
他这个位置就在疯狂判断 新旧节点的文本和子节点
那么 首先 按上次的继续 判断他们为同一个节点
然后 进来先判断 两个节点是不是一模一样的 如果是 那就说明都不做了
如果不是 那就先判断 新节点内容是不是文字 如果进来 那就判断 老节点和新节点的文字是否相同 如果相同 那就还是 什么都不用做了 如果不相同 就将老节点的文本改为新节点的文本 这里 可能有人就会好奇 如果我新节点是文本 但老节点有子节点呢? 那好事啊 我们将文本写入节点要通过 innerText innerText写入内容的同时也会干掉它之前的节点
如果新节点 没有text文本属性 那就判断老节点 有没有子节点children属性
如果老节点没有children 那就直接清空老节点的内容 然后把新节点的children写进去
还有一种情况就说老节点有children 那么就要精细化去处理 两个节点的children 里面的内容了
处理children 深度的比较会麻烦一些这个我们可能要再单独去讲了 好啦 这里主要是个大家滤清思路