Vue中的diff算法


diff 简介

diff 算法是一种优化手段,将前后两个模块进行差异化对比,修补(更新)差异的过程叫做patch(打补丁)

为什么 vue ,react 这些框架中都会有 diff 算法呢?要知道渲染真实 DOM 的开销是很大的,比如有时候我们修改了某个数据,如果直接渲染到真实 DOM 上会引起整个 DOM 树的重绘和重排,有没有可能我们只更新我们修改的那一小块 DOM 而不要更新整个 DOM 呢?diff 算法能够帮助我们。

当数据发生变化时,vue是怎么更新节点的?

我们先根据真实 DOM 生成一棵 virtual DOM(虚拟DOM)树,当 virtual DOM 某个节点的数据改变后会生成一个新的 Vnode(虚拟节点),然后 VnodeoldVnode 作对比,发现有不一样的地方就直接修改在真实的 DOM 上,然后使 oldVnode 的值为Vnode

diff 的过程就是调用名为 patch 的函数,比较新旧节点,一边比较一边给真实的 DOM 打补丁。


virtual DOM(虚拟DOM)

// 真实dom
<div>
  <p>Hello World</p>
</div>

转换成虚拟节点 类似于下面这种(伪代码)

const Vnode = {
  tag:'div',
  children:[
    {tag:'p',text:'Hello World'}
  ]
}

diff 的比较方式

在采取 diff 算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较。

<div>
    <p>123</p>
</div>

<div>
    <span>456</span>
</div>

上面的代码会分别比较同一层的两个div以及第二层的p和span,但是不会拿div和span作比较。
一张很形象的图:(比较只会在同层级进行, 不会跨层级比较
在这里插入图片描述
概括起来就是对操作前后的dom树同一层的节点进行对比,一层一层对比,然后再插入真实的dom中,重新渲染


vue for 循环中 key 的作用

vue中列表循环需加:key="唯一标识" 唯一标识可以是 item 里面 idindex
因为vue组件高度复用增加 Key 可以标识组件的唯一性,那么 Key 是如何更高效的更新虚拟 DOM 的呢,我们看下面的例子:
在这里插入图片描述
我们希望可以在B和C之间加一个F,diff 算法默认执行起来是这样的:即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?

所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。在这里插入图片描述


为什么不建议用index作为key?

不建议 用 index 作为 key,和没写基本上没区别,因为不管你数组的顺序怎么颠倒,index 都是 0, 1, 2 这样排列,导致 Vue 会复用错误的旧子节点,做很多额外的工作

posted @ 2022-07-20 18:15  猫老板的豆  阅读(115)  评论(0编辑  收藏  举报