例子
参考ArrayToArray.js中的 5.1、5.1.1例子
实现
主要3个部分
- 提取新数据的key,旧数据遍历时,用来提取对应key的数据
- 遍历旧数据,找到与旧数据key对应的新数据,赋值给newIndex
- 若newIndex有值,则patch对应newIndex的数据,若没值,直接删除当前下标的旧数据
function patchKeyedChildren(c1, c2, container, parentInstance, anchor) {
if (i > e1 && i <= e2) {
// 新的比老的多,插入数据
// other code
} else if (i > e2 && i <= e1) {
// 新的比老的少,删除数据
// other code
} else {
let s1, s2 = i;
// 新节点的个数,用来判断遍历次数
const toBePatched = e2 - s2 + 1;
// patch 过的次数
let patched = 0;
// 提取新数据的key
const keyToNewIndexMap = new Map();
for (let i = s2; i <= e2; i++) {
const nextChild = c2[i];
keyToNewIndexMap.set(nextChild.key, i);
}
// 遍历老数据,判断当前元素是否在新数据中
for (let i = s1; i < e1; i++) {
// 旧节点当前数据
const prevChild = e1[i];
// 新旧节点对比相同时,存储的新节点对应下标,用于patch对应数据
let newIndex;
// 如果当前 patched 的次数 >= 应该 patch 的总数,则说明是多余的旧数据,直接做删除
if (patched >= toBePatched) {
hostRemove(prevChild.el);
continue;
}
// key不为空,匹配对应key的新数据
if (prevChild.key) {
newIndex = keyToNewIndexMap.get(prevChild.key);
} else {
// 没有key,遍历新数据逐个对比
for (let j = s2; j <= e2; j++) {
if (isSameVNode(prevChild, c2[j])) {
newIndex = j;
break;
}
}
}
// newIndex不为空,新老对比,深度patch
if (newIndex) {
patch(prevChild, c2[newIndex], container, parentComponent, null);
// 每次patch都加一次patched次数
patched++;
} else {
// 没有找到相同数据,则删除当前数据
hostRemove(prevChild.el);
}
}
}