1. 虚拟 DOM 是什么

一个能代表 DOM 树的对象,通常含有标签名标签上的属性事件监听子元素们,以及其他属性

2. 虚拟 DOM 的优点

2.1.减少不必要的 DOM 操作

  1. 虚拟 DOM 可以将多次操作合并为一次操作(减少频率
    1. 比如你添加 1000 个节点,却是一个接一个操作的
  2. 虚拟 DOM 借助 DOM diff 可以把多余的操作省掉(减少范围

    1. 比如你添加 1000 个节点,其实只有 10 个是新增的

      2.2.能跨平台渲染

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

    3. 虚拟 DOM 的缺点

    需要额外的创建函数,如createElementh,但可以通过 JSX 来简化成 XML 写法
    关于创建虚拟 DOM 和简化可见另一篇博客

    4. DOM diff 是什么

    定义:就是虚拟 DOM 的对比算法

  • DOM diff 就是一个函数,我们称之为patch
  • patches = patch(oldVNode, newVNode)(括号里分别表示新旧两个虚拟的 DOM 节点)
  • patches就是要运行的 DOM 操作,可能长这样:
    1. [
    2. {type: 'INSERT', vNode: ... },
    3. {type: 'TEXT', vNode: ... },
    4. {type: 'PROPS', propsPatch: [...]}
    5. ]

    DOM diff 可能的大概逻辑

    1.Tree diff

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

    2.Component diff

    如果节点是组件,就先看组件类型

  3. 类型不同直接替换(删除旧的)

  4. 类型相同则只更新属性
  5. 然后深入组件做 Tree diff(递归)

    3.Element diff

    如果节点是原生标签,则看标签名

  6. 标签名不同直接替换,相同则只更新属性

  7. 然后进入标签后代做 Tree diff(递归)

    示例:将虚拟 DOM 想象成树形

    1. <div :class="x">
    2. <span v-if="y">{string1}</span>
    3. <span>{string2}</span>
    4. </div>
    image.png

    当数据变化时

  • 比如:x 从 red 变成 green
    • 原本:image.png现在: image.png
    • DOM diff 发现
      • div 标签类型没变,只需要更新 div 对应的 DOM 的属性
      • 子元素没变,不更新
  • 再比如:y 从 true 变成 false
    • 原本:image.png 现在: image.png
    • DOM diff 发现
      • div 没变,不用更新
      • 子元素1标签没变,但是children变了,更新 DOM 内容
      • 子元素2不见了,删除对应的 DOM
  • 补充:如果这个元素有 key,那么就会去找到对应的key,看有没有改变

    5. DOM diff 的优点

    前面虚拟DOM已经讲过,就是省去一些多余的DOM操作

    6. DOM diff 的缺点

    同级节点对比存在 bug

    比如上面的那个例子:

  • [x] 明明是删除的第一个节点hello

  • 但是实际却是将第一个节点的hello变成了world

    解决办法:就是给其加上唯一的key,这也就是为什么使用 v-for 的时候必须加上 :key 的原因