vue diff 算法学习

之前跟着视频教程写过一遍虚拟dom的生成和diff 算法, vue 的虚拟dom 来自于 snabbdom 这个库, github代码仓库, 现在重新回顾一遍

diff 算法是干啥的

首先要知道 diff 算法到底是用来干什么的? diff 算法不是在两个集合里寻找不同的元素的, 而是找到符合你判断逻辑的相同虚拟节点。比如:vue里面的 sameNode,下面有代码 ;找到相同虚拟节点之后,执行 patch 逻辑, 这里的patch 是 vue 里面的dom操作 , 这里的sameNode匹配只是判断最外层vnode是否相同, 内部还需要 patch 函数进行操作

diff 算法执行的逻辑

匹配逻辑, 这里的匹配逻辑使用了多个指针一起走, 每一次循环都会执行一次下面的逻辑, 一次循环走过以后, 对应的下标也会改变, 这里注意下标的改变跟命中逻辑有关
在这里插入图片描述

//  diff 算法是用来寻找相同元素进行patch的
      // 下面的方法没有处理边界,
      // 比如你的新标签要比旧的多, 那就需要 diff算法结束后进行一次处理, 把剩余的新标签元素插入到dom中去,
      // 你的新标签如果比旧的少, 那就可能需要你删掉相应的标签

      const sameNode = (newNode, node) => {
        return node.key == newNode.key && node.tag === newNode.tag
      }
      const map = new Map()

      const arr = [
        { key: 1, tag: 'div' },
        { key: 2, tag: 'div' },
        { key: 5, tag: 'div' },
        { key: 4, tag: 'div' }
      ]

      const arr2 = [
        { key: 1, tag: 'div' },
        { key: 2, tag: 'div' },
        { key: 5, tag: 'div' },
        { key: 6, tag: 'div' }
      ]

      let startIndex = 0
      let endIndex = arr.length - 1
      let nStartIndex = 0
      let nEndIndex = arr2.length - 1

      //命中才能改变当前下标,
      while (startIndex <= endIndex && nStartIndex <= nEndIndex) {
        const item = arr[startIndex]
        const endItem = arr[endIndex]
        const nItem = arr2[nStartIndex]
        const nEndItem = arr2[nEndIndex]

        // 新前和旧前的值相等
        if (sameNode(nItem, item)) {
          startIndex++
          nStartIndex++
          console.log('命中了=>现在是新前===旧前', nItem, item)
        } else if (sameNode(nEndItem, endItem)) {
          nEndIndex--
          endIndex--
          console.log('命中了=>现在是新后===旧后', nEndItem, endItem)
        } else if (sameNode(nEndItem, item)) {
          startIndex++
          nEndIndex--
          console.log('命中了=>现在是新后===旧前', nEndItem, item)
        } else if (sameNode(nItem, endItem)) {
          endIndex--
          nStartIndex++
          console.log('命中了=>现在是新前===旧后', nItem, endItem)
        } else {
          console.log('sdfsdfsdfsdf')
          if (map.length === 0) {
            arr.forEach((item, index) => {
              map.set(item.key, index)
            })
          }

          // 匹配有没有命中的元素
          const index = map.get(arr2[nStartIndex].key)

          if (index) {
            console.log('最后一个循环找到了,执行patch')
          } else {
            console.log(
              '直接把旧标签用新的替换掉',
              `${arr2[nStartIndex].key}${arr2[nStartIndex].tag}`
            )
          }

          nStartIndex++
        }
      }

解释:

1. sameNode

const sameNode = (vnode, newVnode)=>{
return vnode.key == newVnode.key && vnode.tag === newVnode.tag
}

推荐去这视频看一遍教程, 就能好好理解虚拟dom和diff算法了

posted @ 2022-05-28 21:37  阿臻  阅读(38)  评论(0编辑  收藏  举报