vue.js中的虚拟DOM

typora-copy-images-to: assets

虚拟DOM介绍

  1. 什么是虚拟DOM
    虚拟DOM是将状态映射成试图的众多解决方案之一。页面交互的本质还是通过改变状态(变量)来改变试图渲染,而框架(像主流框架vue、react、angular)的应用可以让我们把关注的焦点更多的放在状态上,省略对DOM的操作(框架内部已经帮我们完成了)。
    而虚拟DOM映射视图的方式是通过状态生成一个虚拟节点树,然后通过虚拟节点树进行渲染。虚拟节点树本质上是一个普通的js对象,它包含了创建一个DOM元素所需要的属性

  2. 为什么要在vue中引入虚拟DOM

    • 像react(虚拟DOM)、angular(脏检查)对状态变化的侦测都有一个特点:他们不知道那个状态发生了变化,当有状态发生变化时,就对整个视图进行重新渲染。
      // 问题:react angular vue的监听原理对比
      // 1. 脏检查、虚拟DOM、细粒度绑定分别是什么原理
      // 1.1 脏检查:页面所有的数据变动都是由事件或者异步操作触发的。
      // 浏览器提供了监测事件的API,但没有检测数据变化的API。
      // 因此每次在执行一次事件后都会对数据进行大检查,监听那些数据发生了改变。
      // 网址:https://www.zhihu.com/question/43470158/answer/108283135
      // 1.2 虚拟DOM:生成一个类DOM对象,通过这个对象可以生成DOM元素。
      // react是怎么来监听数据变化的呢?
      // 只要页面有事件发生,就会把所有的DOM全部删除,再重新渲染。不会进行DOM对比
      // 1.3 细粒度绑定
      // 基本原理在第二和第三章有讲解
    • 在vue1.0中用的细粒度监听方式,但每一个监听都会对应一个watcher,这样对内存和依赖(请看前面两篇博客)追踪的开销太大。vue2.0中采用中等粒度 + 虚拟DOM的解决方案。既以组件级别为一个依赖实例,组件内部状态的变化监听就由虚拟DOM完成。
  3. vue中的虚拟DOM
    执行渲染函数会生成虚拟树节点,在虚拟DOM渲染视图的过程中,会将新生成的vnode与上一次渲染的vnode进行对比,找出真正需要更新的节点。而这个对比的过程成为patch算法,也是虚拟DOM的核心,后面的博客会讲解到

  4. vnode
    vuejs中有一个Vnode类,通过它可以实例化不同类型的vnode实例,不同类型的vnode实例代表不同类型的DOM元素。DOM元素有元素节点、文本节点、注释节点等,对应的vnode也有不同类型。vnode本质上是js中的一个对象,可以把它理解为节点描述对象
    export default class VNode {
    tag: string | void;
    data: VNodeData | void;
    children: ?Array;
    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
      }
    }
    
    • vnode节点分类
      不同类型的节点之间,只是有效属性不同;比如注释节点有效属性只有text和i你Comment;其余属性默认都是undefiend或者false; 文本节点的有效属性只有text
      1. 注释节点:对应视图中的注释
        export const createEmptyVnode = text => {
        const node = new VNode()
        node.text = text
        node.isComment = true
        return node
        }
        对应的注释节点就是:
        {
        text: ‘注释节点‘,
        isComment: true
        }

      2. 文本节点: 对应视图中的文字,比如我是文本节点中的我是文本节点就是文本节点
        export const createTextVnode = text => {
        return new VNode(undefined, undefined, undefined, string(text))
        }
        对应的文本节点就是:
        {
        text: ‘这是文本节点‘
        }

      3. 克隆节点: 将现有节点的属性复制到新节点当中;作用是优化静态节点和插槽节点;以静态节点为例,静态节点从第一次渲染后,无论页面中的状态怎么发生变化他都不会改变,因此只需第一次渲染的时候获取一下(在模板编译的优化器阶段就已经标注那些节点是静态节点,请看下篇博客)
        本人有个小问题:渲染静态节点的过程难道比优化器的实现过程更加耗费性能吗?

      4. 元素节点:
        常见的属性:

        • tag: 节点名称,对应着DOM元素标签名
        • tata: 包含了一些节点上的数据,如class、style attrs等(具体获取方式请看下篇博客)
        • children: 子节点
        • context: 当前组件的vue实例

vue.js中的虚拟DOM

上一篇:js event loop


下一篇:css padding-right没有用?