一篇文章带你搞懂Vue虚拟Dom与diff算法

  

  

使用过Vue和反应的小伙伴肯定对虚拟Dom和diff算法很熟悉,它扮演着很重要的角色。由于小编接触Vue比较多,反应只是浅学,所以本篇主要针对Vue来展开介绍,带你一步一步搞懂它。

  

  

<强>什么是虚拟DOM ?

  

虚拟DOM (Virtual ,Dom),也就是我们常说的虚拟节点,是用JS对象来模拟真实Dom中的节点,该对象包含了真实Dom的结构及其属性,用于对比虚拟Dom和真实Dom的差异,从而进行局部渲染来达到优化性能的目的。
  真实的元素节点:

        祝辞& lt; div id=" wrap ";   & lt; p类="标题"在Hello world ! & lt;/p>   & lt;/div>   之前      

VNode:

        {   标签:“div ',   attrs: {   id:“包装”   },   孩子:(   {   标签:“p”,   文字:“Hello world !”   attrs: {   类:“标题”,   }   }   ]   }   之前      

<强>为什么使用虚拟DOM ?

  

简单了解虚拟DOM后,是不是有小伙伴会问:Vue和反应框架中为什么会用到它呢?好问题!那来解决下小伙伴的疑问。
  起初我们在使用JS/JQuery时,不可避免的会大量操作DOM,而DOM的变化又会引发回流或重绘,从而降低页面渲染性能。那么怎样来减少对DOM的操作呢?此时虚拟DOM应用而生,所以虚拟DOM出现的主要目的就是为了减少频繁操作DOM而引起回流重绘所引发的性能问题的!

  

<强>虚拟DOM的作用是什么?

  
      <李>兼容性好。因为Vnode本质是JS对象,所以不还管节点是浏览器环境,都可以操作,李   <李>减少了对Dom的操作。页面中的数据和状态变化,都通过Vnode对比,只需要在比对完之后更新Dom,不需要频繁操作,提高了页面性能,李   
  

<强>虚拟DOM和真实DOM的区别?

  

说到这里,那么虚拟DOM和真实DOM的区别是什么呢?总结大概如下:

  
      <李>虚拟DOM不会进行回流和重绘,李   <李>真实DOM在频繁操作时引发的回流重绘导致性能很低;李   <李>虚拟DOM频繁修改,然后一次性对比差异并修改真实DOM,最后进行依次回流重绘,减少了真实DOM中多次回流重绘引起的性能损耗;李   <李>虚拟DOM有效降低大面积的重绘与排版,因为是和真实DOM对比,更新差异部分,所以只渲染局部;李   
  
  

总损耗=真实DOM增删改+(多节点)回流/重绘,,,,//计算使用真实DOM的损耗
  总损耗=虚拟DOM增删改+ (diff对比)真实DOM差异化增删改+(较少节点)回流/重绘,,,//计算使用虚拟DOM的损耗

     

可以发现,都是围绕频繁操作真实DOM引起回流重绘,导致页面性能损耗来说的。不过框架也不一定非要使用虚拟DOM,关键在于看是否频繁操作会引起大面积的DOM操作。

  

那么虚拟DOM究竟通过什么方式来减少了页面中频繁操作DOM呢?这就不得不去了DOM Diff解算法了。

  

  

当数据变化时,vue如何来更新视图的?其实很简单,一开始会根据真实DOM生成虚拟DOM,当虚拟DOM某个节点的数据改变后会生成一个新的Vnode,然后Vnode和oldVnode对比,把不同的地方修改在真实DOM上,最后再使得oldVnode的值为Vnode。

  
  

diff过程就是调用补丁函数,比较新老节点,一边比较一边给真实DOM打补丁(补丁);

     

对照vue源码来解析一下,贴出核心代码,旨在简单明了讲述清楚,不然小编自己看着都头大了O (∩_∩) O

  

<强>补丁

  

那么补丁是怎样打补丁的?

     //补丁函数oldVnode:老节点vnode:新节点   功能块(oldVnode vnode) {   …   如果(sameVnode (oldVnode vnode)) {   patchVnode (oldVnode vnode)//如果新老节点是同一节点,那么进一步通过patchVnode来比较子节点   其他}{/* - - - - - -否则新节点直接替换老节点- - - - - - */const oEl=oldVnode。el//当前oldVnode对应的真实元素节点   让parentEle=api.parentNode (oEl)//父元素   createEle (vnode)//根据vnode生成新元素   如果(parentEle !==null) {   api。方法(parentEle vnode。el, api.nextSibling (oEl))//将新元素添加进父元素   api。作用是:parentEle oldVnode.el)//移除以前的旧元素节点   oldVnode=零   }   }   …   返回vnode   }//判断两节点是否为同一节点   函数sameVnode (a, b) {   回报(   一个。===b的关键。关键,,//键值   一个。标签===b。标签,,//标签名   一个。isComment===b。isComment,,//是否为注释节点//是否都定义了数据,数据包含一些具体信息,例如onclick,风格   isDef (a.data)===isDef (b.data),,   sameInputType (a, b)//当标签是& lt; input>的时候,类型必须相同   )   }   

一篇文章带你搞懂Vue虚拟Dom与diff算法