iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >vue2的diff算法怎么使用
  • 621
分享到

vue2的diff算法怎么使用

2023-07-04 14:07:27 621人浏览 泡泡鱼
摘要

这篇文章主要介绍“Vue2的diff算法怎么使用”,在日常操作中,相信很多人在vue2的diff算法怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue2的diff算法怎么使用”的疑惑有所帮助!接下来

这篇文章主要介绍“Vue2的diff算法怎么使用”,在日常操作中,相信很多人在vue2的diff算法怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue2的diff算法怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

vue2的diff过程

  • 比较方式: 同级比较,不会跨级比较

以下源码来自vue/patch.ts,会有一些提取,相关函数会附上链接。

patch函数
  • diff过程就是调用 patch函数,比较新旧节点,一边比较一边给真实DOM打补丁,那么我们就先来看一下patch函数:

  • 源码地址:  patch函数,isUndef()函数,isDef()函数, emptynodeAt函数

  return function patch(oldVnode, vnode, hydrating, removeOnly) {      if (isUndef(vnode)) {  //新的节点不存在          if (isDef(oldVnode)) //旧的节点存在          invokeDestroyHook(oldVnode)   //销毁旧节点          return       }         .........      //isRealElement就是为处理初始化定义的,组件初始化的时候,没有oldVnode,那么Vue会传入一个真实dom      if (!isRealElement && sameVnode(oldVnode, vnode)) { -----判断是否值得去比较        patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly) ---打补丁,后面会详细讲      } else {        ......         if (isRealElement)          ......          oldVnode = emptyNodeAt(oldVnode) //转化为Vnode,并赋值给oldNode        }        // replacing existing element        const oldElm = oldVnode.elm      ----找到oldVnode对应的真实节点        const parentElm = nodeOps.parentNode(oldElm)  ------找到它的父节点        createElm(.....) --------创建新节点        ....递归地去更新节点    return vnode.elm  }

vue2的diff算法怎么使用

sameNode函数
  • 其中出现了sameNode,判断是否值得我们去给他打补丁,不值得的话就按照上述步骤进行替换,我们还是去寻找一下这个函数

  • 源码地址: sameNode函数

function sameVnode(a, b) {  return (        a.key === b.key &&  ----------------------key值相等, 这就是为什么我们推荐要加上key,可以让判断更准确    a.asyncFactory === b.asyncFactory &&     ((a.tag === b.tag && ---------------------标签相等      a.isComment === b.isComment && ---------是否为注释节点      isDef(a.data) === isDef(b.data) &&  ----比较data是否都不为空      sameInputType(a, b)) ||  ---------------当标签为input的时候,需要比较type属性      (isTrue(a.isAsyncPlaceholder) && isUndef(b.asyncFactory.error)))  )}
  • 如果值得我们去给他打补丁,则进入我们patchVNode函数

patchVNode
  • 源码地址: patchVNode函数

  • 这个函数有点长,也是做了一下删减

  function patchVnode(...  ) {    if (oldVnode === vnode) {  //两个节点一致,啥也不用管,直接返回      return    }    ....    if (    //新旧节点都是静态节点,且key值相等,则明整个组件没有任何变化,还在之前的实例,赋值一下后直接返回      isTrue(vnode.isStatic) &&      isTrue(oldVnode.isStatic) &&      vnode.key === oldVnode.key &&      (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))    ) {      vnode.componentInstance = oldVnode.componentInstance      return    }    const oldCh = oldVnode.children  //获取旧节点孩子    const ch = vnode.children //获取新节点孩子    if (isUndef(vnode.text)) { //新节点没有文本      if (isDef(oldCh) && isDef(ch)) {  //旧节点孩子和新节点孩子都不为空        if (oldCh !== ch) //旧节点孩子不等于新节点孩子          updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly) //重点----比较双方的孩子进行diff算法       } else if (isDef(ch)) {  //新节点孩子不为空,旧节点孩子为空         ....        addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue) //新增节点       } else if (isDef(oldCh)) {  //新节点孩子为空,旧节点孩子不为空        removeVnodes(oldCh, 0, oldCh.length - 1)  //移除旧节点孩子节点      } else if (isDef(oldVnode.text)) {  //旧节点文本为不为空        nodeOps.setTextContent(elm, '')  //将节点文本清空      }    } else if (oldVnode.text !== vnode.text) { //新节点有文本,但是和旧节点文本不相等      nodeOps.setTextContent(elm, vnode.text) //设置为新节点的文本    }  }
  • 这里的判断很多,所以我也加了个流程图

vue2的diff算法怎么使用

updateChildren(diff算法的体现)
  • 源码地址:updateChildren函数

  • 这里采用四步走的形式,我把代码都拆分出来了

初始化
  • 采用的四个指针分别指向四个节点

    • oldStartIdxnewStartIdx 指向旧节点头,新节点头, 初始值为0

    • oldEndIdxnewEndIdx 指向旧节点尾,新节点尾,初始值为长度-1

    let oldStartIdx = 0 //旧头指针    let newStartIdx = 0 //新头指针    let oldEndIdx = oldCh.length - 1  //旧尾指针    let newEndIdx = newCh.length - 1 //新尾指针    let oldStartVnode = oldCh[0] //旧头结点    let oldEndVnode = oldCh[oldEndIdx] //旧尾结点    let newStartVnode = newCh[0] //新头结点    let newEndVnode = newCh[newEndIdx]  //新尾结点

vue2的diff算法怎么使用

四次比较-循环中
  • 旧头和新头

  • 旧尾和新尾

  • 旧头和新尾

  • 旧尾和新头

注意: 这里只要能够命中一个,就重开,都不能命中的话再看下一环节, 而不是继续挨个判断vue2的diff算法怎么使用

  function updateChildren(){  ·....   //好戏从这里开始看   //只要满足 旧头指针<=旧尾指针 同时  新头指针<= 新尾指针 -- 也可以理解为不能交叉    while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {    //这里进行一个矫正,是应该在循环的过程中,如果进入key表查询的话复用后会将旧节点置空(后面会说),所以这里会对其进行一个处理      if (isUndef(oldStartVnode)) {  //旧头结点为空        oldStartVnode = oldCh[++oldStartIdx] // 往右边走      } else if (isUndef(oldEndVnode)) {  //旧尾结点为空        oldEndVnode = oldCh[--oldEndIdx] //往左边走    //step1      } else if (sameVnode(oldStartVnode, newStartVnode)) {  //比较旧头和新头,判断是否值得打补丁        patchVnode(...) //打补丁        oldStartVnode = oldCh[++oldStartIdx]  //齐头并进向右走        newStartVnode = newCh[++newStartIdx]  //齐头并进向右走    //step2      } else if (sameVnode(oldEndVnode, newEndVnode)) {  //比较旧尾和新尾, 判断是否值得打补丁        patchVnode(...) //打补丁        oldEndVnode = oldCh[--oldEndIdx]  //齐头并进向左走        newEndVnode = newCh[--newEndIdx]  //齐头并进向左走   //step3      } else if (sameVnode(oldStartVnode, newEndVnode)) { //比较旧头和新尾,判断是否值得打补丁        patchVnode(...) //打补丁        //补完移动节点        canMove && nodeOps.insertBefore(parentElm,oldStartVnode.elm,nodeOps.nextSibling(oldEndVnode.elm))        oldStartVnode = oldCh[++oldStartIdx]  //旧头向右走        newEndVnode = newCh[--newEndIdx] //新尾向左走    //step4      } else if (sameVnode(oldEndVnode, newStartVnode)) {  //比较旧尾和新头,判断是否值得打补丁        patchVnode(...) //打补丁        //补完移动节点        canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)        oldEndVnode = oldCh[--oldEndIdx]  //旧尾向左走        newStartVnode = newCh[++newStartIdx] //新头向右走      }

实践来一下,就拿上面随机来的例子吧

  • step1 、step2

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • step3 、step4(命中)

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 在step4进行处理,移动节点到正确位置(插在旧头的前面)vue2的diff算法怎么使用

  • 旧尾向左走,新头向右走vue2的diff算法怎么使用

  • 处理完后就重开,从step1开始,到step2再次命中,此时oldEndInxnewEndInx齐头并进向左走(注意这里是不用去移动节点的哦)(左), 然后重开,在step2再次命中...(右)

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 重开, 这次在step3命中,然后将旧头结点结点的真实节点插在旧尾结点的后面,到这里其实真实节点就已经是我们所期望的了

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 上述处理完后,旧头向右走,新尾向左走,命中step1,新头和旧头都向左走,出现交叉情况,至此退出循环

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 通过上面这个例子,我们把四种情况都命中了一下(一开始随便画的图没想到都命中了哈哈哈),也成功通过复用节点将真实结点变为预期结果,这里便是双端diff一个核心体现了

  • 但是如果四种情况都没有命中的呢(如图下)vue2的diff算法怎么使用

  • 则会走向我们最后一个分支,也就是后面介绍的列表寻找vue2的diff算法怎么使用

列表寻找-循环中
  • 先来看懂里面涉及到的createKeyToOldIdx函数

  • 源码地址: createKeyToOldIdx函数

function createKeyToOldIdx(children, beginIdx, endIdx) {  let i, key  const map = {}  //初始化一个对象  for (i = beginIdx; i <= endIdx; ++i) { //从头到尾    key = children[i].key  //提取每一项的key    if (isDef(key)) map[key] = i  //key不为空的时候,存入对象,键为key,值为下标  }  return map  //返回对象}//所以该函数的作用其实就是生成了一个节点的键为key,值为下标的一个表
  • 再来看一下里面涉及到的findIdxInOld函数

  • 源码地址:findIdxInOld函数

  function findIdxInOld(node, oldCh, start, end) {  //其实就是进行了一个遍历的过程    for (let i = start; i < end; i++) {      const c = oldCh[i]      if (isDef(c) && sameVnode(node, c)) return i  //判断是否有值得打补丁的节点,有则返回    }  }
  • 进入正文

 let oldKeyToIdx, idxInOld, vnodeToMove, refElm; ....else {        if (isUndef(oldKeyToIdx))          oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx) //传入的是旧节点孩子,所以生成了一个旧节点孩子的key表          //使用三目运算符--- 这里也是要使用key的原因,key有效的话可以通过表获取,无效的话则得进行比遍历比较        idxInOld = isDef(newStartVnode.key)  //判断新头结点的key是否不为空--是否有效          ? oldKeyToIdx[newStartVnode.key]  //不为空的的话就到key表寻找该key值对象的旧节点的下标          : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx) //遍历寻找旧节点数组中是否有和新头结点值得打补丁的节点,有的话则赋值其下标给idxInOld(不通过key)        if (isUndef(idxInOld)) {  //发现找不到了就直接创建新真实节点          createElm(...)        } else { //找到了          vnodeToMove = oldCh[idxInOld] //找到该下标对应的节点          if (sameVnode(vnodeToMove, newStartVnode)) { //进行一个比较判断是否值得打补丁            patchVnode(...) //打补丁             oldCh[idxInOld] = undefined  //置空,下次生成表就不会把它加进去            canMove &&nodeOps.insertBefore( parentElm, vnodeToMove.elm,oldStartVnode.elm ) //移动节点          } else {          //不值得打补丁,创建节点            createElm(...)          }        }        newStartVnode = newCh[++newStartIdx]  //新头指针向前一步走      }    } //--- while循环到这里
  • 看完源码其实可以总结一下,就是前面四个都没有命中后,就会生成旧节点孩子key

  • 新头节点的key有效的话,就拿新头节点的key去旧节点的key表找,找不到就创建新的真实节点, 找得到的话就判断是否值得打补丁,值得的话就打补丁后复用节点,然后将该旧节点孩子值置空,不值得就创建新节点

  • 新头节点的key无效的话,则去遍历旧节点数组挨个进行判断是否值得打补丁,后续跟上述一样

  • 新头指针向前一步走

也使用一下上面的例子运用一下这个步骤,以下都为key有效的情况vue2的diff算法怎么使用

(重新放一下图,方便看)

  • 生成了一个旧节点的key表(key为键,值为下标), 然后newStartVnodekey值为B,找到旧节点孩子该节点下标为1,则去判断是否直接打补丁,值得的话将该旧节点孩子置空再在A前面插入B

vue2的diff算法怎么使用vue2的diff算法怎么使用

右图的表中B没有变为undefined是因为表示一开始就生成的,在下次进入循环的时候生成的表才会没有B

  • 然后将新头向右走一步,然后重开,发现前四步依旧没有命中,此时新头结点为B,但是生成的旧节点表没有B,故创建新的节点,然后插入

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 新头继续向右走,重开,命中step1(如图左), 之后新头和旧头齐头并进向右走, 此时,旧头指向的undefined(图右),直接向右走,重开

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 发现此时又都没有命中, 此时也是生成一个key表,发现找不到,于是创建新节点M插入

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 然后新头继续向前走,依旧都没有命中,通过key表去寻找,找到了D,于是移动插入,旧节点孩子的D置空,同时新头向前一步走

vue2的diff算法怎么使用vue2的diff算法怎么使用

  • 走完这一步其实就出现交叉情况了,退出循环,此时如下图,你会发现,诶,前面确实得到预期了,可是后面还有一串呢

vue2的diff算法怎么使用

  • 别急,这就来处理

处理
    if (oldStartIdx > oldEndIdx) { //旧的交叉了,说明新增的节点可能还没加上呢      refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm      addVnodes(....) //新增    } else if (newStartIdx > newEndIdx) {  //新的交叉了,说明旧节点多余的可能还没删掉呢      removeVnodes(oldCh, oldStartIdx, oldEndIdx) //把后面那一段删掉    }
  • 对于上面这个例子,就是把后面那一段,通过遍历的方式,挨个删除vue2的diff算法怎么使用

Vue的优点

Vue具体轻量级框架、简单易学、双向数据绑定、组件化、数据和结构的分离、虚拟DOM、运行速度快等优势,Vue中页面使用的是局部刷新,不用每次跳转页面都要请求所有数据和dom,可以大大提升访问速度和用户体验。

到此,关于“vue2的diff算法怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: vue2的diff算法怎么使用

本文链接: https://www.lsjlt.com/news/345665.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • vue2的diff算法怎么使用
    这篇文章主要介绍“vue2的diff算法怎么使用”,在日常操作中,相信很多人在vue2的diff算法怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue2的diff算法怎么使用”的疑惑有所帮助!接下来...
    99+
    2023-07-04
  • Vue2中的Diff算法怎么使用
    这篇文章主要介绍了Vue2中的Diff算法怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue2中的Diff算法怎么使用文章都会有所收获,下面我们一起来看看吧。为什么要用 Diff 算法虚拟 DOM因为...
    99+
    2023-07-05
  • vue2中的VNode和diff算法怎么使用
    本文小编为大家详细介绍“vue2中的VNode和diff算法怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue2中的VNode和diff算法怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。什么是...
    99+
    2023-07-04
  • Vue2 diff算法怎么掌握
    今天小编给大家分享一下Vue2 diff算法怎么掌握的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是 diff 在我的理...
    99+
    2023-07-05
  • 深入浅析Vue2中的Diff算法
    为什么要用 Diff 算法虚拟 DOM因为 Vue2 底层是用虚拟 DOM 来表示页面结构的,虚拟 DOM其实就是一个对象,如果想知道怎么生成的,其实大概流程就是:首先解析模板字符串,也就是 .vue 文件然后转换成 AST 语法树接着生成...
    99+
    2023-05-14
    diff算法 Vue.js 前端
  • Vue2 的 diff 算法规则原理详解
    目录前言算法规则diff 优化策略老数组的开始与新数组的开始老数组的结尾与新数组的结尾老数组的开始与新数组的结尾老数组的结尾与新数组的开始以上四种情况都没对比成功推荐在渲染列表时为节...
    99+
    2024-04-02
  • 一文搞懂vue2 diff算法(附图)
    patch函数diff过程就是调用 patch函数,比较新旧节点,一边比较一边给真实DOM打补丁,那么我们就先来看一下patch函数:源码地址: patch函数,isUndef()函数,isDef()函数, emptyNodeAt函数 ...
    99+
    2022-11-22
    Vue
  • 深入理解vue2中的VNode和diff算法
    虚拟dom和diff算法是vue学习过程中的一个难点,也是面试中必须掌握的一个知识点。这两者相辅相成,是vue框架的核心。今天我们再来总结下vue2中的虚拟dom 和 diff算法。(学习视频分享:vue视频教程)什么是 VNode我们知道...
    99+
    2022-11-22
    VNode diff算法 Vue vue.js
  • 深入了解Vue2中的的双端diff算法
    目录简单diff算法更新文本节点key的作用如何移动呢双端diff算法比较方式非理想情况的处理方式今天又重读了vue2的核心源码,主要之前读vue2源码的时候纯属的硬记,或者说纯粹的...
    99+
    2023-02-08
    Vue双端diff算法 Vue diff算法
  • 快速搞懂Vue2 diff算法(图文详解)
    前置内容既然是对比新旧 VNode 数组,那么首先肯定有 对比 的判断方法:sameNode(a, b)、新增节点的方法 addVnodes、移除节点的方法 removeVnodes,当然,即使 sameNode 判断了 VNode 一致之...
    99+
    2023-05-14
    Vue2 Vue diff算法
  • vue3 diff算法怎么应用
    这篇文章主要介绍“vue3 diff算法怎么应用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue3 diff算法怎么应用”文章能帮助大家解决问题。一、可能性(常见):旧的:a...
    99+
    2023-07-02
  • vue怎么实现diff算法
    这篇文章主要介绍“vue怎么实现diff算法”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue怎么实现diff算法”文章能帮助大家解决问题。 模块路径:src\...
    99+
    2024-04-02
  • Vue中的双端diff算法怎么应用
    这篇文章主要讲解了“Vue中的双端diff算法怎么应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue中的双端diff算法怎么应用”吧!Vue 和 React 都是基于 vdom 的前端...
    99+
    2023-07-02
  • react的diff方法怎么使用
    今天小编给大家分享一下react的diff方法怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。react的diff方法...
    99+
    2023-07-04
  • Vue的双端diff算法怎么实现
    这篇文章主要介绍了Vue的双端diff算法怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue的双端diff算法怎么实现文章都会有所收获,下面我们一起来看看吧。前言Vue 和 React 都是基于 vd...
    99+
    2023-07-02
  • React怎么实现核心Diff算法
    本篇内容主要讲解“React怎么实现核心Diff算法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“React怎么实现核心Diff算法”吧!Diff算法的设计思路试想,Diff算法需要考虑多少种情...
    99+
    2023-06-30
  • 怎么深入解析Vue3中的diff 算法
    今天给大家介绍一下怎么深入解析Vue3中的diff 算法。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。1.0  diff 无key子节点在处理被标记...
    99+
    2023-06-26
  • Vue的diff算法原理是什么
    这篇文章将为大家详细讲解有关Vue的diff算法原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。思维导图0. 从常见问题引入虚拟dom是什么如何创建虚拟dom虚拟dom如何渲染成真是dom虚拟do...
    99+
    2023-06-29
  • vue2从数据变化到视图变化之diff算法图文详解
    目录引言1、isUndef(oldStartVnode)2、isUndef(oldEndVnode)3、sameVnode(oldStartVnode, newStartVnode)...
    99+
    2024-04-02
  • React中diff算法是什么
    这篇文章主要介绍了React中diff算法是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。React中diff算法的理解diff算法用来计算出Virtual DOM中改变...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作