用四个指针分别指向新旧子节点的头尾,然后反别对比各种情况进行DOM的位置调换。
function patchKedChildren2(n1, n2, container) {const oldChildren = n1.childrenconst newChildren = n2.children//四个索引let oldStartIndex = 0let oldEndIndex = oldChildren.length - 1let newStartIndex = 0let newEndIndex = newChildren.length - 1//四个节点let oldStartVNode = oldChildren[oldStartIndex]let oldEndVNode = oldChildren[oldEndIndex]let newStartVNode = newChildren[newStartIndex]let newEndVNode = newChildren[newEndIndex]//循环while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) {if (!oldStartVNode) {oldStartVNode = oldChildren[++oldStartIndex]} else if (!oldEndVNode) {oldEndVNode = oldChildren[--oldEndIndex]//当新旧初始节点一样时} else if (oldStartVNode.key === newStartVNode.key) {//更新一下节点patch(oldStartVNode, newStartVNode, container)//指针指向下一个oldStartVNode = oldChildren[++oldStartIndex]newStartVNode = newChildren[++newStartIndex]//新旧子节点的末尾节点key一样} else if (oldEndVNode.key === newEndVNode.key) {//更新一下节点patch(oldEndVNode, newEndVNode, container)//指针指向上一个oldEndVNode = oldChildren[--oldEndIndex]newEndVNode = newChildren[--newEndIndex]//旧字节点的开始节点和新子节点的结束节点一样} else if (oldStartVNode.key === newEndVNode.key) {patch(oldStartVNode, newEndVNode, container)//将旧开始节点的el插入到旧结束节点的后面insert(oldStartVNode.el, container, oldEndVNode.el.nextSibling)//改变指针oldStartVNode = oldChildren[++oldStartIndex]newEndVNode = newChildren[--newEndIndex]//新字节点的开始节点和旧子节点的结束节点一样} else if (newStartVNode.key === oldEndVNode.key) {patch(oldEndVNode, newStartVNode, container)//将旧字节点末尾的el插入到旧子节点开始的el 的前面insert(oldEndVNode.el, container, oldStartVNode.el)//改变指针newStartVNode = newChildren[++newStartIndex]oldEndVNode = oldChildren[--oldEndIndex]} else {//如果都找不到//直接找新字节点头 ,在旧子节点中的对应位置const index = oldChildren.findIndex((c) => {return c && newStartVNode.key === c.key})if (index > 0) {//更新patch(oldChildren[index], newStartVNode, container)//旧子节点index处el插入到旧子节点头el前insert(oldChildren[index].el, container, oldStartVNode.el)//旧字节点index处置undefinedoldChildren[index] = undefined} else {//添加新元素patch(null, newStartVNode, container, oldStartVNode.el)}//新子节点头指针进一newStartVNode = newChildren[++newStartIndex]}}//添加遗漏节点if (oldEndIndex < oldStartIndex && newEndIndex >= newStartIndex) {for (let i = newStartIndex; i <= newEndIndex; i++) {patch(null, newChildren[i], container, oldStartVNode.el)}//删除节点} else if (newEndIndex < newStartIndex && oldEndIndex >= oldStartIndex) {for (let i = oldStartIndex; i <= oldEndIndex; i++) {unmount(oldChildren[i])}}}
