28-更新element-children-3

75 阅读1分钟

例子

参考ArrayToArray.js中的 5.1、5.1.1例子

实现

主要3个部分

  1. 提取新数据的key,旧数据遍历时,用来提取对应key的数据
  2. 遍历旧数据,找到与旧数据key对应的新数据,赋值给newIndex
  3. 若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);
        }
 }
}

图实例

等长的情况

vue-diff-03.gif

数据超出

vue-diff-04.gif