上文我们简单描述了patch处理同一节点的大体逻辑
这次 我们就来看一下text替换的情况
我们更改案例入口文件 src下的 index.js 代码如下
import h from "./snabbdom/h";
import patch from "./snabbdom/patch";
const container = document.getElementById("container");
const vnode = h("section", {}, [
h("p", {}, "1A"),
h("p", {}, "2B"),
h("p", {}, "3C")
]);
patch( container, vnode)
const btn = document.getElementById("btn");
const vnode1 = h("section", {},"你好");
btn.onclick = function(){
patch( vnode, vnode1)
}
这里 我们一开始是一个section 里面是三个p标签 更换时 section是文本
我们运行项目
然后我们点击更改dom按钮
并没有任何的反应 因为我们还没有写
我们找到patch.js中判断 当新旧节点为同一节点的处理区块
编写代码如下
//判断 如果 新旧虚拟节点完全相同 则不做操作 直接返回
if(oldVnode === newVnode) return;
/*
判断新节点的text是不是空的 包括就算text是空字符串 也算有 只要不是undefined未定义
同时 也要判断 要newVnode没有children 或 children 是个空数组
*/
if(newVnode.text != undefined&&(!newVnode.children||!newVnode.children.length)) {
//确定一下新旧节点的text文本是不是不同 如果相同就什么都不用做了
if(newVnode.text !== oldVnode.text) {
//利用innerText将新节点的text写入到老节点的elm中 因为 elm 存的是真实的dom
oldVnode.elm.innerText = newVnode.text;
}
}else{
//否则就算新节点没有text
}
这里 我们编写的逻辑是
首先 我们先用 === 绝对等于 确定新旧节点到底是不是同一个节点 如果是 那就说明都不做了
然后判断 新节点有没有text文本属性
因为 我们这里判断的是 他的text等于undefined 就算是个空字符串都进得来
所以 走到else那就一定是没有 其次 判断了他的子节点字段children如果拿不到或者为空的 才会往里面走
所以 暂时 我们只考虑文本情况 else的逻辑先放着
然后继续往下 我们判断 新旧节点的文本是不是真的不一样 如果一样 我们就不处理了 如果不一样 直接将新节点的text通过innerText写入到旧节点的elm
我们之前也说过 旧节点的 elm 存的就是真实的dom位置
innerText写入的好处在于 它不但会将你的文本写入 他还会干掉之前节点的文本和子节点 也就不需要我们考虑之前有没有子节点了
我们再次运行项目
然后点击更改dom
这里 我们的文本就写入成功了
然后 我们再来处理另一种情况
反过来 旧节点上是文字 新节点上带子节点
src下index.js 将 vnode和vnode1 调h的第三个函数换一下就好了
但这种分两种情况 首先比较简单的是我们现在的情况 老的没有子节点 新的有
还有一种就是 新旧都有子节点 就要继续去递归精细化比较 会非常麻烦
我们先写第一种 老的文本 新的有子节点的情况
来到 patch.js 刚才写的 那个判断新节点有没有text文本和字节的if下
现在我们来写else的代码
我们在里面这样写
//判断老节点有没有children
if(oldVnode.children&&oldVnode.children.length) {
//新旧节点都有children的情况 最复杂 先不处理
} else {
//新的有children 老的没有
//通过innerHTML 清空老节点中的内容
oldVnode.elm.innerHTML = "";
//二者都有children 就算最复杂的情况
newVnode.children.map(item => {
let dom = createElement(item);
oldVnode.elm.appendChild(dom);
})
}
这里进来 我们先判断 旧节点有没有 children 如果有 那就麻烦了 需要对新旧两个节点的 children 做比较 我们这里先不管
否则 就是 新的有 children 旧的没有 那么 我们就先用innerHTML将旧节点中无论是内容还是节点 全部干掉
然后循环将新节点的子节点children循环遍历出来 都通过createElement创建成真实的孤儿节点 然后插入到老节点的下方
然后 我们运行项目
点击更改dom
可以看到之前的文本就干掉了 新节点也挂上去了
好啦 那么 子节点换文字 和 文字换子节点 甚至你们可以试一下 写到这里文字换文字也可以了
只留了一个最麻烦的 子节点换子节点的逻辑我们后面再继续出文 讲解啦