虚拟DOM

定义

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

优点

1、减少DOM 操作
虚拟 DOM 可以将多次操作合并为一次操作(减少频率)

虚拟 DOM 借助 DOM diff 可以把多余的操作省掉(减少范围)
2、可以跨平台
虚拟 DOM 本质上只是一个 JS 对象 (可以变成 DOM,还可以变成小程序、iOS 应用、安卓应用

缺点

需要额外的创建函数,如createElement 或 h,但可以通过 JSX 来简化成 XML 语法

虚拟DOM

在React中的虚拟DOM

  1. const vNode = {
  2. key: null,
  3. props: {
  4. children: [
  5. {type: 'span', ...},
  6. {type: 'span', ...}
  7. ],
  8. className: "red",
  9. onClick: ()=>{}
  10. },
  11. ref: null,
  12. type: "div",
  13. ...
  14. }

在Vue中的虚拟DOM

  1. const vNode = {
  2. tag: 'div',
  3. data: {
  4. class: 'red',
  5. on: {
  6. click: ()=>{}
  7. }
  8. },
  9. children: [
  10. {tag: "span", ...},
  11. {tag: "span", ...}
  12. ],
  13. ...

创建虚拟DOM

React

  1. createElement('div',{className:'red',onClick:()=> {}},[
  2. createElement('span', {}, 'span1'),
  3. createElement('span', {}, 'span2')
  4. ]
  5. )
  6. // 通过 JSX 简化
  7. <div className="X" onClick="{()=> {}}">
  8. <span>span1</span>
  9. <span>span2</span>
  10. </div>
  11. // 通过 babel 转为 createElement 形式

Vue

  1. // 只能在 render 函数里得到 h
  2. h('div', {
  3. class: 'red',
  4. on: {
  5. click: () => { }
  6. },
  7. }, [h('span',{},'span1'), h('span', {}, 'span2'])
  8. // 通过简化JSX
  9. <div class="red" @click="fn">
  10. <span>span1</span>
  11. <span>span2</span>
  12. </div>
  13. // 通过 vue-loader 转为 h 形式

DOM Diff

DOM diff其实就是一个函数,它会对比 oldNode 与 newNode 的区别。从而减少不必要的渲染。但是DOM diff会有bug(可以使用key解决)

  • Tree diff :将新旧两棵 DOM 树,按照层级对应的关系,这样只需要对树进行一次遍历,就能够找到哪些元素是需要更新的; 如果节点是组件就看 Component diff ; 如果节点是标签就看 Element diff。

  • Component Diff: 在对比每一层的时候,每一层都有自己的组件, 那么组件之间的对比,叫做 Component diff

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

  • Element Diff : 如果新旧 DOM 树中的组件类型相同,会继续比较这两个组件内部的元素是否也相同,如果元素发生了改变,则找到需要修改的元素,有针对性的修改,这种组件内部元素级别的对比叫: Element Diff;

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