源码分析
patch
虚拟dom更新的时候,会执行update,update方法中又会调用patch,根据新旧Vnode对比转换成真正的 DOM 节点,所以diff算法用在patch过程中
patch主要做了四个判断:
- 没有新节点,直接触发旧节点的destory钩子;
- 没有旧节点,说明是页面刚开始初始化的时候,此时,根本不需要比较了,直接全部都是新建,所以只调用 createElm;
- 旧节点和新节点自身一样,通过 sameVnode 判断节点是否一样,一样时,直接调用 patchVnode 去处理这两个节点;
- 旧节点和新节点自身不一样,当两个节点不一样的时候,直接创建新节点,删除旧节点;
patchVnode
patchVnode主要做了几个判断:
- 新节点是否是文本节点,如果是,则直接更新dom的文本内容为新节点的文本内容;
- 新节点和旧节点如果都有子节点,则处理比较更新子节点;
- 只有新节点有子节点,旧节点没有,那么不用比较了,所有节点都是全新的,所以直接全部新建就好了,新建是指创建出所有新DOM,并且添加进父节点;
- 只有旧节点有子节点而新节点没有,说明更新后的页面,旧节点全部都不见了,那么要做的,就是把所有的旧节点删除,也就是直接把DOM 删除;
updateChildren
该方法主要将新旧节点的children数组进行前后指针的对比:
- 前面4个条件列出了4中比较结果的处理,如果前面4个条件都不满足,则进行单个遍历查找;
单个遍历查找
拿新子节点的子项,直接去旧子节点数组中遍历,找一样的节点出来流程大概是
- 生成旧子节点数组以vnode.key为key的map表;
- 拿到新子节点数组中一个子项,判断它的key是否在上面的map中;
- 不存在,则新建DOM,并插入oldStartVnode 前面;
- 存在,继续判断是否sameVnode,如果相同,直接移动到 oldStartVnode 前面;如果不同,直接创建插入 oldStartVnode 前面;
- 处理剩下的节点,新子节点遍历完毕,旧子节点可能还有剩,所以我们要对可能剩下的旧节点进行 批量删除!就是遍历剩下的节点,逐个删除DOM;
- 旧子节点遍历完了,新子节点可能有剩,所以要对剩余的新子节点处理,很明显,剩余的新子节点不存在 旧子节点中,所以全部新建;
diff流程图
vue系列课程
最近会陆续的对vue进行源码分析,一系列课程如下: