【一起读】深入浅出Vue.js——虚拟DOM之VNode

前文提到,vue使用虚拟DOM中主要做了两件事,一个是创建了VNode来模拟DOM树,另一个是通过patch算法比对新旧DOM的变更状态。本节主要介绍VNode相关,包括VNode是什么?VNode有什么作用?

6.1 VNode是什么

VNode是一个类,使用他可以实例化各种类型的vnode实例,不同的DOM元素对应不同类型的vnode。

class VNode{
    constructor (
        tag?: string,
        data?: VNodeData,
        children?: ?Array<VNode>,
        text?: string,
        elm?: Node,
        context?: Component,
        componentOptions?: VNodeComponentOptions,
        asyncFactory?: Function
    ) {
        this.tag = tag // 当前节点标签名
        this.data = data // 当前节点数据(VNodeData类型)
        this.children = children // 当前节点子节点
        this.text = text // 当前节点文本
        this.elm = elm // 当前节点对应的真实DOM节点
        this.ns = undefined // 当前节点命名空间
        this.context = context // 当前节点上下文
        this.fnContext = undefined // 函数化组件上下文
        this.fnOptions = undefined // 函数化组件配置项
        this.fnScopeId = undefined // 函数化组件ScopeId
        this.key = data && data.key // 子节点key属性
        this.componentOptions = componentOptions // 组件配置项 
        this.componentInstance = undefined // 组件实例
        this.parent = undefined // 当前节点父节点
        this.raw = false // 是否为原生HTML或只是普通文本
        this.isStatic = false // 静态节点标志 keep-alive
        this.isRootInsert = true // 是否作为根节点插入
        this.isComment = false // 是否为注释节点
        this.isCloned = false // 是否为克隆节点
        this.isOnce = false // 是否为v-once节点
        this.asyncFactory = asyncFactory // 异步工厂方法 
        this.asyncMeta = undefined // 异步Meta
        this.isAsyncPlaceholder = false // 是否为异步占位
    }

    // 容器实例向后兼容的别名
    get child (): Component | void {
        return this.componentInstance
    }
}

不同类型的vnode有不同的属性,更具体的说法是:不同类型的vnode有不同的有效属性。当使用VNode实例化一个vnode时,通过参数为实例设置属性时,无效的属性会默认被赋值为undefined或false。

根据DOM元素种类的不同,一共有六种vnode类型,分别是:注释节点、文本节点、元素节点、组件节点、函数式组件、克隆节点。

6.1.1 注释节点

创建一个注释节点:

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

一个注释节点只有两个有效属性,text和isComment,其余属性是默认值undefined和false。
举例一行注释代码:

 <!-- 我是注释 -->

这行代码对应的vnode为:

{
  text: "我是注释",
  isComment: true
}
6.1.2 文本节点

创建一个文本节点:

export const createTextVNode = (val) => {
   return new VNode(undefined, undefined, undefined, String(val))
}

文本节点只有一个有效属性就是 text:

{
  text: '我是文本',
}
6.1.3 克隆节点

克隆节点即字面意思,将一个节点克隆到一个新节点上面,好处是可以优化静态节点和插槽节点。静态节点除了首次渲染需要执行渲染函数获取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=vnode.isCloned
    if(deep&&vnode.children){
        cloned.children=cloneVNode(vnode.children)
    }
    return cloned;
}

克隆节点与被克隆节点的区别是isCloned属性。

6.1.4 元素节点
<div class="demo">
        <span class="test">哈哈哈</span>
      </div>

上述代码对应的vnode为:

{
    tag: 'div',
    data: {
        class: 'demo',
    },
    children: [
        {
            tag: 'span',
            data: {
                class:'test'
                 },
            text: '哈哈哈'
        }
]
}

元素节点有四个有效属性:

  • tag:节点的名称,如p div span 等
  • data:元素的属性 如class attrs style等
  • children:当前节点的子节点列表
  • context:当前组件的Vue.js实例
6.1.5 组件节点

组件节点与元素节点类似,多了两个个独有属性:

  • componentOptions:组件节点的选项参数,包括propsData,tag,children等
  • componentInstance:组件的实例,即Vue.js的实例
6.1.6 函数式组件

函数式组件与组件节点类似,额外多了两个独有属性:

  • functionContext
  • functionOptions

6.2 VNode有什么作用

渲染视图时,先模拟真实的DOM元素创建vnode,使用vnode渲染DOM节点,在每次渲染时,先将vnode缓存起来,下一次渲染时,通过比对新旧vnode的不同来修改真实的DOM元素。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容