- 预处理
- j从新旧子节点头部开始处理相同key节点
- 两指针从两子节点尾开始处理相同节点
- 新节点如果已处理完,旧节点没有处理完,卸载旧节点
- 旧节点已处理完,新节点没有处理完,逐个插入新节点
新旧节点都没处理完
- 找到新节点对应的旧节点索引,如[2,3,1,-1]
- -1代表新节点需要插入
- 计算最长递增子序列
- 从新节点尾部往前遍历
如果不在最长子序列中,说明需要将当前节点的DOM往后移、
function patchKedChildren3(n1, n2, container) {const oldChildren = n1.childrenconst newChildren = n2.children//预处理let j = 0let oldVNode = oldChildren[j]let newVNode = newChildren[j]while (newVNode.key === oldVNode.key) {patch(oldVNode, newVNode, container)j++oldVNode = oldChildren[j]newVNode = newChildren[j]}let oldEndIndex = oldChildren.length - 1let newEndIndex = newChildren.length - 1oldVNode = oldChildren[oldEndIndex]newVNode = newChildren[newEndIndex]while (newVNode.key === oldVNode.key) {patch(oldVNode, newVNode, container)oldEndIndex--newEndIndex--oldVNode = oldChildren[oldEndIndex]newVNode = newChildren[newEndIndex]}//如果旧子节点已处理结束,新子节点没有,则新增if (oldEndIndex < j && newEndIndex >= j) {const anchorIndex = newEndIndex + 1const anchor =anchorIndex < newChildren.length ? newChildren[anchorIndex].el : nullwhile (j <= newEndIndex) {patch(null, newChildren[j], container, anchor)j++}//如果新子节点已处理结束,旧子节点没有,则卸载全部未处理旧子节点} else if (newEndIndex < j && oldEndIndex >= j) {while (j <= oldEndIndex) {unmount(oldChildren[j++])}//处理交换位置} else {const count = newEndIndex - j + 1const source = new Array(count)source.fill(-1)const indexMap = {}const pos = 0const newStart = jconst oldStart = j//indexMap存储形式{key,index}for (let i = newStart; i <= newEndIndex; i++) {indexMap[newChildren[i].key] = i}let patched = 0let move = falsefor (let i = oldStart; i <= oldEndIndex; i++) {const oldVNode = oldChildren[i]if (patched > count) {const k = indexMap[oldVNode.key]if (k) {const newVNode = newChildren[ind]patched++patch(oldVNode, newVNode, container)source[k - newStart] = iif (k < pos) {move = true} else {pos = k}} else {unmount(oldVNode)}} else {unmount(oldVNode)}}//递增子序列,不需移动const seq = getSequence(source)//s指向递增子序列最后let s = seq.length - 1//i指向需要移动的子节点最后let i = count - 1for (i; i >= 0; i--) {//等于-1说明是新增需要插入if (source[i] === -1) {//children中的位置const pos = i + newStartconst anchorIndex = pos + 1const anchor = newChildren[anchorIndex]? newChildren[anchorIndex].el: nullpatch(null, newChildren[pos], container, anchor)//i比当前seq指针位置小,说明i处的新子节点需要移到最后} else if (i !== seq[s]) {if (i < seq[s]) {const pos = i + newStartconst anchorIndex = pos + 1const anchor = newChildren[anchorIndex]? newChildren[anchorIndex].el: nullinsert(newChildren[pos].el, container, anchor)}//节点一样s上移一位} else {s--}}}}
