Skip to content

Latest commit

 

History

History
120 lines (94 loc) · 4.18 KB

1.6.Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法.md

File metadata and controls

120 lines (94 loc) · 4.18 KB

关于Vue中的VNode

在浏览器中我们可以通过js来操作DOM,但是这样的操作性能很差,因为真正的DOM元素非常庞大,于是Virtual Dom应运而生。可以这样理解,Virtual Dom就是在js中模拟DOM对象树来优化DOM操作的一种技术或思路。

下面先来看看Vue中的Virtual Dom,源码位置在src/core/vdom/vnode.js

export default class VNode {
  tag: string | void;
  data: VNodeData | void;
  children: ?Array<VNode>;
  text: string | void;
  elm: Node | void;
  ns: string | void;
  context: Component | void;
  key: string | number | void;
  componentOptions: VNodeComponentOptions | void;
  componentInstance: Component | void;
  parent: VNode | void;

  //...
  constructor (
    tag?: string, // vNode的标签,例如div、p等标签
    data?: VNodeData, // vNode上的data值,包括其所有的class、attribute属性、style属性
    children?: ?Array<VNode>, // vNode上的子节点
    text?: string, // 文本
    elm?: Node, // vNode上对应的真实dom元素
    context?: Component, // vdom的上下文
    componentOptions?: VNodeComponentOptions,
    asyncFactory?: Function
  ) {
    this.tag = tag
    this.data = data
    this.children = children
    this.text = text
    this.elm = elm
    this.ns = undefined
    this.context = context
    //...
  }
  //...
}

从上面源码可以看出,Virtual Dom相对浏览器中的真实Dom要简单得多。其实Vue中的Virtual Dom就是把真实Dom中一些常用的属性类型,再加上Vue里面的一些配置项组成的。

Vue中的Virtual Dom不仅对真实浏览器Dom进行简化外,还对不同场景进行了Virtual Dom的分类。下面是EmptyVNode、TextVNode、CloneVNode的创建,源码位置在src/core/vdom/vnode.js

// EmptyVNode
export const createEmptyVNode = (text: string = '') => {
  const node = new VNode()
  node.text = text
  node.isComment = true
  return node
}

// TextVNode
export function createTextVNode (val: string | number) {
  return new VNode(undefined, undefined, undefined, String(val))
}

// CloneVNode
export function cloneVNode (vnode: VNode): VNode {
  const cloned = new VNode(
    vnode.tag,
    vnode.data,
    vnode.children && vnode.children.slice(),
    vnode.text,
    vnode.elm,
    vnode.context,
    vnode.componentOptions,
    vnode.asyncFactory
  )
  cloned.ns = vnode.ns
  cloned.isStatic = vnode.isStatic
  cloned.key = vnode.key
  cloned.isComment = vnode.isComment
  cloned.fnContext = vnode.fnContext
  cloned.fnOptions = vnode.fnOptions
  cloned.fnScopeId = vnode.fnScopeId
  cloned.asyncMeta = vnode.asyncMeta
  cloned.isCloned = true
  return cloned
}

关于Virtual Dom的分类,除了上面三种外, 还有ElementVnode,ComponentVnode等。

关于VNode的创建这里就不多说,在"Vue模板编译-AST生成Render字符串"那一节内容中我们就说了生成Render字符串中_c就是createElement创建VNode,还不清楚的可以回头再看一下。

Vue中的DOM diff原理

比较两棵DOM树的差异是 Virtual DOM 最核心的部分,这也是所谓的 Virtual DOM 的diff算法。 它的作用就是根据两个虚拟对象创建出描述改变内容的补丁,将这个补丁用来更新DOM。

两个Dom树的 diff 算法是一个时间复杂度为 O(n^3) 的问题,但实际上在前端当中,很少会跨越层级地移动DOM元素。即Virtual DOM 只会对同一个层级的元素进行对比,这样算法复杂度就可以达到 O(n)。

Vue中的Patch 补丁更新

Vue中的VNode生命周期

总结一下

最后,在这里总结一下Vue中Virtual Dom执行过程:

1.用JS对象模拟DOM树,即调用createElement生成VNode

2.比较两棵虚拟DOM树的差异

3.把差异应用到真正的DOM树上

相关