1. 比较顺序
Diff 算法在比较两个节点的时候,只会在同层进行比较,而不会跨层比较,所以可以使用双端交叉算法。
2. 算法概述
2.1 含有类型
Vue 中含有的类型一般为如下类型,而 React 包含的类型为 tag, props, children;
{
"tag": "xxx",
"key": "xxx",
"elm": "xxx",
"text": "xxx",
"data": {...},
"children": [{...}, ...]
}
2.2 比较根节点
首先使用 patch(oldVnode, vnode) 方法比较两个根节点:
- 新节点不存在,直接删除整个旧节点;
- 新节点存在,旧节点不存在,新增整个新节点;
- 判断它们的
tag 类型是否相同,相同则仅更新属性即可; - 若二者皆为文本类型,若文本信息不同,则更新文本节点;
2.3 比较孩子节点
- vnode 的孩子节点不存在,oldVnode 孩子节点存在,则直接删除整个孩子节点;若孩子节点为文本类型,则清空文本;
- vnode 孩子节点存在,oldVnode 孩子节点不存在,直接新增整个孩子节点;
- 二者都存在,使用
updateChildren(elm, oldCh, ch)比较孩子节点,使用双端交叉算法比较- 使用四个指针:oldStartIdx、oldEndIdx、newStartIdx、newEndIdx;
- 依次进行
头头比较、尾尾比较、前头后尾、前尾后头;若相同,则前指针后移,后指针前移; - 若发现上述四个均不相同,则使用 key 进行比较。将 oldVnode 中的 key -> index 保存在 Map 中,然后使用 vnode 中的 key 查找,若找到,则
将找到的 oldVnode 中对应的 index 处的内容置为 undefined,然后指针移动,直到 oldStartIdx >= oldEndIdx 或者 newStartIdx >= newEndIdx,这时删掉旧节点,增添新节点即可。