【Vue】虚拟DOM

281 阅读2分钟

1. WHAT-Virtual DOM

真正的DOM元素是非常庞大的树形数据结构,而Virtual DOM本质上是一种轻量级的JavaScript数据格式,用于表示真实DOM在给定时间点的外观。Virtual DOM只是一个对象,它会有一个标签,表示它是一个div,它还有一个数据对象,其中包含可能的属性,它还可以存在一个子列表,表示更多的虚拟节点的数组。这样就可以构成虚拟DOM的虚拟节点树。

  • 真实DOM

realDOM.png 可以看到,真正的DOM元素是非常庞大的,当我们频繁的去做DOM的更新操作时,会产生一定的性能问题。

  • 虚拟DOM
      {
        "tag": "h1",
        "children": [
          {
            "text": ""
          }
        ],
        ......
      }
    
    Virtual DOM就是用一个原生的JS对象去描述一个DOM节点。在Vue中是通过VNode这个Class类去描述定义虚拟DOM的。
      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; // rendered in this component's scope
        key: string | number | void;
        componentOptions: VNodeComponentOptions | void;
        componentInstance: Component | void; // component instance
        parent: VNode | void; // component placeholder node
    
        // strictly internal
        raw: boolean; // contains raw HTML? (server only)
        isStatic: boolean; // hoisted static node
        isRootInsert: boolean; // necessary for enter transition check
        isComment: boolean; // empty comment placeholder?
        isCloned: boolean; // is a cloned node?
        isOnce: boolean; // is a v-once node?
        asyncFactory: Function | void; // async component factory function
        asyncMeta: Object | void;
        isAsyncPlaceholder: boolean;
        ssrContext: Object | void;
        fnContext: Component | void; // real context vm for functional nodes
        fnOptions: ?ComponentOptions; // for SSR caching
        fnScopeId: ?string; // functional scope id support
    
        constructor (
          tag?: string,
          data?: VNodeData,
          children?: ?Array<VNode>,
          text?: string,
          elm?: Node,
          context?: Component,
          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
          this.fnContext = undefined
          this.fnOptions = undefined
          this.fnScopeId = undefined
          this.key = data && data.key
          this.componentOptions = componentOptions
          this.componentInstance = undefined
          this.parent = undefined
          this.raw = false
          this.isStatic = false
          this.isRootInsert = true
          this.isComment = false
          this.isCloned = false
          this.isOnce = false
          this.asyncFactory = asyncFactory
          this.asyncMeta = undefined
          this.isAsyncPlaceholder = false
        }
    
        // DEPRECATED: alias for componentInstance for backwards compat.
        /* istanbul ignore next */
        get child (): Component | void {
          return this.componentInstance
        }
      }
    
    其中包含了一些Vue的特性。

2. WHY-Virtual DOM

虚拟DOM的出现当然是为了性能而考虑的,假设我们有1000个元素的列表。创建1000个JavaScript对象,可以很快,但是创建1000个实际的div节点却会消耗太多的性能。VNode是对真实DOM的一种抽象描述,它的核心定义包含几个关键属性,标签名、数据、子节点、键值等,其他属性都是用来扩展VNode的灵活性以及实现一些特殊feature的。由于VNode只是用来映射到真实DOM的渲染,不需要包含操作DOM的方法,因此它是非常轻量和简单的。