虚拟DOM和DOM diff

204 阅读3分钟

虚拟DOM和DOM diff

虚拟DOM

虚拟DOM概念

是一个能代表DOM树的 JavaScript 对象,包含了 tagpropschildren 三个属性。

创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应

<div id="app">
  <p class="text">hello world!!!</p>
</div>

上面的 HTML 转换为虚拟 DOM 如下:

{
  tag: 'div',
  props: {
    id: 'app'
  },
  chidren: [
    {
      tag: 'p',
      props: {
        className: 'text'
      },
      chidren: [
        'hello world!!!'
      ]
    }
  ]
}

该对象就是我们常说的虚拟 DOM 了,因为 DOM 是树形结构,所以使用 JavaScript 对象就能很简单的表示。

虚拟DOM优点
  • 减少操作

    将多次操作合并为一个操作,如添加1000个节点不必手动一次一次添加,可以一次性完成。(减少次数)

    DOM diff更加灵活以操作。 如已有90个节点,想再添加10个节点,简单的JS无法判断新增,只能将其合并为100个进行添加。但diff可以判断10个新增节点,这样可以省却多余的操作。(减少范围)

  • 跨平台

    虚拟 DOM 不仅可以变成 DOM,还可以变成小程序、iOS 应用、安卓应用,因为虚 拟 DOM 本质上只是一个 JS 对象

虚拟DOM缺点

​ 需要额外的创建函数,如 createElement 或 h,但可以通过 JSX 来简化成 XML 写法。当数据繁杂时,虚拟DOM还是会崩溃,原生DOM则不会。以节点为例,增设十万个节点的时候虚拟DOM常常会崩溃。

DOM diff

DOM diff概念

diff其实就是different缩写!!!

diff 算法,顾名思义,就是比对新老 VDOM 的变化,然后将变化的部分更新到视图上。

该改变原理如下:

我们将其想象成树状图:

8.png 当我们准备删掉带有“hello”的这条的时候,会变成如下情况:

9.png

这个过程的原理在于,diff会先将 “hello” 改变成 "world",然后将带有 “world”的这条span删除。 先后经历了两个步骤。

DOM diff 可能的样式
[
  {type: ‘INSERT’, vNode: ... },//插入节点
  {type: ‘TEXT’,  vNode: ... },//更新文本
  {type: ‘PROPS’, propsPatch: [...]}//更新属性
]

显而易见,dom diff可以减少我们很多操作,其优点就是虚拟dom的优点。

DOM diff的逻辑

Tree diff

  • 将新旧两棵树逐层对比,找出哪些节点需要更新
  • 如果节点是组件就看 Component diff
  • 如果节点是标签就看 Element diff

Component diff

  • 如果节点是组件,就先看组件类型
  • 类型不同直接替换(删除旧的)
  • 类型相同则只更新属性
  • 然后深入组件做 Tree diff(递归)

Element diff

  • 如果节点是原生标签,则看标签名
  • 标签名不同直接替换,相同则只更新属性
  • 然后进入标签后代做 Tree diff(递归)
DOM diff 问题

DOM diff的逻辑虽然使用起来很方便,但是有个硬伤:

​ 在没有表明key属性的情况下,你无法删除你想要删除的那个它!

例子:

首先,在三个 input 里依次输入三角形、正方形和圆形。(这里没有布置key属性)

10.png

当我们删除正方形这一栏

11.png

很奇怪,尽管2被删除了,但正方形还是正方形。为什么呢?

就像前面所说的原理,diff会先把 正方形的2 这个属性改成 3,然后再删除 圆形 这一栏。

想真正删除正方形这一栏,必须加上key。

我们先将数组{1,2,3}加上属性id,这里的id就是我们作为key的标识,即:

{ id: 1 }, { id: 2 }, {id: 3 }

图像就变成这样:

15.png

接着我们删除正方形这一栏:

16.png

这时候就成功了,这时正方形就不会出现了。

值得注意的是:

​ **我们不能将index作为key。**因为index具有连续性的,假设0,1,2中,我们删掉1,那么顺序就会变成0,1,并不会变成1,2.这样就会陷入我们之前所说的你无法删除你想要的那个他了。