用四个指针分别指向新旧子节点的头尾,然后反别对比各种情况进行DOM的位置调换。
function patchKedChildren2(n1, n2, container) {
const oldChildren = n1.children
const newChildren = n2.children
//四个索引
let oldStartIndex = 0
let oldEndIndex = oldChildren.length - 1
let newStartIndex = 0
let 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处置undefined
oldChildren[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])
}
}
}