33-mini-vue 更新element的children-双端对比diff算法

更新element的children-双端对比diff算法

  1. 中间对比

  2. 案例

    • a b ( c y e ) f g < -------- >
    • a b ( e d c ) f g
  3. 情况分析

    • 创建新的(d) (在老的里面不存在,新的里面存在)
    • 删除老的(y) (在老的里面存在,新的里面不存在)
    • 移动(c,e) (节点存在于新的和老的里面,但是位置变了)
  4. 针对相应的情况进行实现功能

    1. 老节点里面有,新节点里面无 如何进行判断呢
      • 遍历新节点进行查找是否存在老节点,我们使用双端对比,减少了O(n) 里面的 n
      • 直接使用 key来进行判断,时间空间复杂度属于 O(1)
    2. 测试案例
    js 复制代码
    // 5.1 
    // a b ( c d ) f g
    // a b ( e c ) f g
    // d 节点在新的里面是没有的 - 需要删除掉
    // c 节点 props 也发生了变化
    const prevChldren = [
      h('p', { key: 'A'}, "A"),
      h('p', { key: 'B'}, "B"),
      h('p', { key: 'C', id: 'c-prev'}, "C"),
      h('p', { key: 'D'}, "D"),
      h('p', { key: 'F'}, "F"),
      h('p', { key: 'G'}, "G"),
    ]
    const nextChildren = [
      h('p', { key: 'A'},'A'),
      h('p', { key: 'B'},'B'),
      h('p', { key: 'E'},'E'),
      h('p', { key: 'C', id: 'c-next'},'C'),
      h('p', { key: 'F'},'F'),
      h('p', { key: 'G'},'G')
    ]
  5. 实现过程

    1. 观察我们发现上面的测试案例, prevChildren 与 nextChildren ,我们先研究的点是

      • 新的里面没有D,进行删除
      • 新的里面 C 的 id 属性值不同,进行修改
    2. 功能实现

    js 复制代码
    // 新的比老的多
    if (i > e1) {
      if (i <= e2) {
        const nextPos = i + 1
        const anchor = nextPos < l2 ? c2[nextPos].el : null
        while (i <= e2) {
          patch(null, c2[i], container, parentComponent, anchor)
          i++
        }
      }
      // 老的比新的多
    } else if (i > e2) {
      while (i <= e1) {
        hostPatchRemove(c1[i].el)
        i++
      }
    } else {
      // ✅ 中间对比
      let s1 = i
      let s2 = i
      let toBePatched = e2 - s2 + 1 // ✅ 优化
      let patched = 0 // ✅ 优化
      const keyToNewIndexMap = new Map()
    
      for (let i = s2; i <= e2; i++) { // 将新节点的每个元素的 key 存入 map
        const nextChild = c2[i]
        keyToNewIndexMap.set(nextChild.key, i)
      }
    
      for (let i = s1; i <= e1; i++) {
        const prevChild = c1[i]
        if (patched >= toBePatched) { // ✅ 优化
          hostPatchRemove(prevChild.el)
          continue;
        }
        // null,unfined
        let newIndex
        // ✅ 看老节点的 key 能不能和新节点匹配上
        if (prevChild.key != null) {
          newIndex = keyToNewIndexMap.get(prevChild.key)
        } else {
          for (let j = s2; j <= e2; j++) {
            if (isSameVNodeType(prevChild, c2[j])) {
              newIndex = j
              break
            }
          }
    
        }
        if (newIndex === undefined) { // ✅ 新节点里面没有,就把老节点删除
          hostPatchRemove(prevChild.el)
        } else { // ✅ 新节点里面有就进行对比渲染
          patch(prevChild, c2[newIndex], container, parentComponent, null)
          patched++
        }
      }
    }
相关推荐
To_OC5 小时前
别再瞎写 React Router!7 个高频踩坑点一次性讲透
前端·javascript·react.js
坚持编程的菜鸟7 小时前
模拟实现memmove
c语言·算法·模拟实现memmove
岭南灯火8 小时前
前端通用交互式几何编辑器的设计法则 3 - 数据对象的设计
前端·javascript·架构
岭南灯火8 小时前
前端通用交互式几何编辑器的设计法则 2 - 交互事件流
前端·javascript·架构
岭南灯火8 小时前
前端通用交互式几何编辑器的设计法则 1 - 入口的对象及其成员
前端·javascript·架构
wabs6668 小时前
关于图论【最短路径之Dijkstra算法(堆优化版)|卡码网47.参加科学大会的思考】
数据结构·算法·图论·优先级队列·邻接表·小顶堆·卡码网
满栀5858 小时前
Vue.js 接口封装最佳实践:从基础到高级
前端·javascript·vue.js
坚持编程的菜鸟8 小时前
编写判断大小端程序
c语言·算法·判断大小端
papaofdoudou8 小时前
判断排列逆序奇偶性的乘积判别法(范德蒙德符号法)
人工智能·算法
linux-hzh9 小时前
百日算法修炼 · Day 03
java·算法