美文网首页
认识vue虚拟DOM(二)

认识vue虚拟DOM(二)

作者: 打静爵 | 来源:发表于2019-06-23 22:28 被阅读0次

    什么是vnode

    在vue中,存在一个VNode类,使用它可以实例化不同类型的vnode实例,不同类型的vnode实例各自表示不同类型的DOM元素。
    例如,DOM元素有元素节点,文本节点和注释节点等,vnode实例就对应着元素节点,文本节点等信息。

    export default class VNode {
        constructor (tag, data, children, text, elm, context, componentOptions, asyncFactory) {
            this.tag = tag
            this.data = data
            this.children = children
            this.elm = elm
            this.ns = undefined
            this.context = this.context
            this.functionalContext = undefined
            this.functionalScopeId = undefined
            this.functionalOptions = 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
        }
        get child () {
            return this.componentInstance
        }
    }
    
    

    从上面代码可以看到,vnode是从VNode实例化的一个普通的JavaScript对象,用这个对象来描述一个真实DOM元素的话,那么该DOM元素上所有的属性在VNode对象上存在对应的属性。

    简单的说,vnode可以理解成节点描述对象,她描述了应该怎样去创建真实的DOM节点。


    vnode创建DOM并插入到视图

    VNode的作用

    由于每次渲染视图都是先创建vnode,然后使用它创建真实DOM插入到页面中,所以可以将上一次渲染视图时所创建的vnode缓存起来,之后每当需要重新渲染视图时,将新创建的vnode和上一次缓存的vnode对比,查看它们之间的不同地方,找出这些不同点再去修改真实DOM。
    vue目前对状态的侦测策略采用了中等粒度。


    变化侦测通知到组件级别

    如图,当某个状态发生改变时,只通知到组件级别,然后组件内使用虚拟DOM来渲染视图,也就是说组件中众多状态中有一个发生变化,那么整个组件就要重新渲染,很明显这样会造成很大的性能浪费。所以,vnode进行缓存并和当前新建的vnode进行对比,只更新变化的节点就显得尤为重要。

    VNode类型

    vnode的类型有以下几种:
    1、 注释节点
    2、 文本节点
    3、 元素节点
    4、 组件节点
    5、 函数式组件
    6、 克隆节点
    当使用VNode类创建一个vnode时,通过参数为实例设置属性时,无效的属性会默认被赋值为undefined或者false,所以下面只讨论vnode有哪些有效属性。

    注释节点:
    由于创建注释节点过程简单,直接代码说明它的属性:

    export const createEmptyVNode = text => {
        const node = new VNode()
        node.text = text
        node.isComment = true
        return node
    }
    

    可以看到,一个注释节点只有两个有效属性:text和isComment,其余默认undefined或者false
    例如,一个真实的注释节点:

    <!--    注释节点  -->
    

    所对应的vnode如下:

    text: '注释节点',
    isComment: true
    

    文本节点:
    当文本类型被创建时,有个一个text属性:

    {
      text: 'hello, world'
    }
    

    克隆节点:
    克隆节点是将现有节点的属性复制到新的节点中,让新创建的节点和被克隆节点属性保持一致,它的作用是优化静态节点和插槽节点。
    以静态节点为例,当组件的某个状态发生变化后 ,当前组件会通过虚拟DOM重新渲染视图,静态节点因为它的内容不会改变,所以除了首次渲染需要执行渲染函数获取vnode外,后续更新不需要执行渲染函数重新生成vnode,此时会使用创建克隆节点的方法将vnode克隆一份,使用克隆节点进行渲染,这样就不需要重新执行渲染函数生成新的静态节点的vnode,从而提升一定的性能。

    export function cloneVNode (vnode, deep) {
        const cloned = new VNode () {
            vnode.tag,
            vnode.data,
            vnode.children,
            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.isCloned = true
        if (deep && vnode.children) {
            cloned.children = cloneVNode(vnode.children)
        }
    }
    

    可以看到,克隆现有节点时,只需要将现有节点属性复制到新的节点即可。克隆节点和被克隆节点之间唯一区别是isCloned属性,克隆节点的isCloned为true,被克隆的原始节点为false

    元素节点:
    元素节点通常有以下4个有效属性:
    tag:节点名称
    data: 该属性包含了一些节点上的数据,比如attrs, class和style等
    children: 字节点列表
    context: 当前组件vue实例
    例如,一个真实元素节点:

    <p><span>hello</span><span>world</span></p>
    
    {
      children: [VNode, VNode],
      context: {...},
      data: {...},
      tag: 'p',
      ...
    }
    

    组件节点:
    组件节点和元素节点类似,但有两个独有属性:
    componentOptions: 组件节点的选项参数,其中包含propsData、tag和children等信息。
    componentInstance: 组件实例

    函数式组件:
    有两个独有属性:
    functionalContext和functionalOptions
    通常一个函数组件vnode如下:

    {
     componentInstance: {...},
     componentOptions: {...},
     context: {...},
     data: {...},
     tag: 'div'
    }
    

    总结

    VNode是一个类,可以生成不容类型的vnode实例,对应不同类型的真实DOM元素。
    由于vue采用了虚拟DOM更新视图,当属性变化时,整个组件都要进行重新渲染的操作,但组件内并不是所有DOM节点都要更新,所以将vnode缓存并将新生成的vnode进行对比,只更新变化部分以提升性能。

    相关文章

      网友评论

          本文标题:认识vue虚拟DOM(二)

          本文链接:https://www.haomeiwen.com/subject/lciwqctx.html