之前我们也见证了 diff算法 的强大 但他 只有确认是同一个节点才做对比 如果不是就直接暴力拆卸了
我们打开我们的案例 找到 node_modules 下面的snabbdom/src下面的 init.ts文件
init.ts 拉到最下面 我们就可以看到这个返回的patch函数
patch相比于他的功能 代码算比较少的了 因为 他里面调用了很多其他函数 就相当于他是一个中转站 将逻辑交给其他函数去处理
我们移下来 看到下图位置
这里 判断 如果第一个元素 是一个真实节点 而不是虚拟节点
那么 我们回忆一下 我们调用patch 什么时候第一个参数传一个真实节点
对 第一次渲染
我们第一次 第一个参数是渲染在什么节点上 第二个参数是个虚拟节点
从第二次开始才是传两个虚拟节点
然后 我们按住Ctrl 点到这个方法来看一下
这个方法比较简单说
就获取一下class id 然后第一个参数 或者一下参数的标签名 用来传选择器
然后调用vnode
vnode 函数 我们之后h函数的时候也讲过这个函数了 就是创建一个虚拟节点
简单说 这个函数的目的 就是将一个不同节点改成虚拟节点
这里 需要注意的是 TS语法函数 变量名后面 : 后代表参数的类型 而Element表示是一个节点 这是一个真正的DOM 节点 因为虚拟节点类型其实是一个对象
这一块代码 就是我们之前说的 只有确认为同一个虚拟节点 才进行精细化比较
这块 else中就是判断 不是同一个节点之后 暴力拆除的方法
直接createElm一个节点
然后removeVnodes掉老节点
然后 我们来捋一下流程 首先 进入patch 他会先判断 第一个节点是不是一个真实的节点
如果是虚拟节点就继续往下 如果是 真实节点 就将他转为虚拟节点
然后 再判断 第一和第二个参数是不是同一个虚拟节点 如果是 对两个参数精细化比较
如果不是 就直接暴力拆除然后插入新的节点
在整个过程中 最难的肯定就算这个精细化比较
首先 我们来搞清楚一个事 怎么判断两个参数 是不是同一个虚拟节点
init.ts中我们可以看到 是通过这里的sameVnode函数 判断的
我们按住Ctrl点进去
他在这里 就用这些属性通过 === 绝对等于进行比较 全部都一样 表示是同一个节点
其中 sel 选择器 就是 你是什么标签 这个要完全相同
判断两者 data中的 is 是否相同 这个对象的问号是TS中的操作符 表示 如果对象中有这个字段 就返回这个字段 如果没有 就返回 undefined
然后判断连个节点的key
这里 如果都没有 那就都是undefined 条件也算会成立的 但标签名选择器这个肯定是不会为空的
然后后面一个需要解释的就是 这个 如果不是相同节点 暴力拆除 然后插入新的
这里这个插入新的是个递归 我们需要看一下
按住Ctrl 我们点击这个createElm进去看一下
然后 这里面有个for循环
首先 想一下为什么要递归
先看会我们之前自己写的 index.js的这个地方
首先 经过刚才的整理 大家应该也明白这个container进入patch都会经历什么了 他其实不像大家理解的那样 变成虚拟节点的容器 而是他会被转为虚拟接单 然后被检查与第二个节点不一样 会被暴力拆掉 然后把第二个这个我们自己写的div虚拟节点换掉
这个是很多人会误解的地方
然后从上面的vonm这个虚拟节点 我们也就 明白了为什么要递归了 你不能值创建一层啊
就 我们创建完div 还要继续创建它下面的p啊
所以这个就有点麻烦
回到 init.ts 我们确认他的确是个递归 for中明显看到了它在自己调用自己
好 这样 我们就能把patch做的事大体梳一遍了 下一篇文章 我会和大家一起手写一个自己的 patch 函数