Vue.js之虚拟节点VNode

众所周知,Vue.jsMVVM 框架结构,其特色在于核心重点关注视图层,而虚拟节点(以下简称 VNode)是这一核心的重要支柱(另一根支柱我觉得是实现响应式框架用到的 Watcher)。下面我们稍微深挖一下 VNode 的“背景”。


一、初识

首先看下 VNode 的类定义:

/**
 * tag - 标签类型,例如 p、div
 * data - 标签上的数据,例如 style、class、data-*
 * children - 顾名思义,子节点
 * text - 文本内容
 * elm - 虚拟节点绑定的真实 DOM 节点
 * context - 一般是 Vue 实例
 * componentOptions - 父组件传给子组件的属性
 */
var VNode = function VNode(tag, data, children, text, elm, context, componentOptions, asyncFactory) {
    this.tag = tag;
    this.data = data;
    this.children = children;
    this.text = text;
    this.elm = elm;
    this.ns = undefined;
    this.context = context;
    this.key = data && data.key;
    this.parent = undefined;
    this.raw = false;
    this.componentOptions = componentOptions;
    // ... 还有些属性我就不列出来了,大家可以自行去看源码
};

从定义可以看出,VNode 纯粹是对 View 层的映射,仅有属性,没有方法。

接着看下 VNode 对节点的解释方式:以简单节点 <p>Hello</p> 为例,其会被解释成2个 VNode 的。一个是 tag 类型为 p ,但没有 text 值的节点,下文称为标签节点;另一个是没有 tag 类型,但是有 text 值的节点,下文称为文本节点

再来了解下 VNode解析流程,看下面的代码

<div id="app">
  <h1 class="h1" style="color:red;" data-id="1">Hello world</h1>
  <div id="wrap">
    <p id="text1">日期:2017-11-9</p>
    <p id="text2">时间戳:1510196747299</p>
  </div>
</div>

大家不妨可以先考虑下,这个页面结构会被拆成多少个节点,再来看下面各个 VNode 的创建顺序:

  1. 文本节点 Hello world
  2. 标签节点 h1
  3. 文本节点 日期:2017-11-9
  4. 标签节点 p#text1
  5. 文本节点 时间戳:1510196747299
  6. 标签节点 p#text2
  7. 标签节点 div#wrap
  8. 标签节点 div#app

从上面的列表可以看出 Vue 对节点的解析是自上而下,从内到外解析的。那么当页面结构中含有 component 会如何解析呢?样例我就不写了,直接给个结果:Vue 会先解析主文档,然后解析组件,而父文档中的组件位置就是组件解析完之后的挂载点。


二、Q & A

1. Q:为什么VNode的解析顺序是自上而下的,从内到外的

A:因为当你写的 HTML 经过 parseHTML 的方法后会产生类似如下的函数

/**
 * _s = toString 方法
 * _v = 创建文本节点
 * _c = 创建标签节点
 */
function f() {
 with (this) {
   return _c(
     'div', { attrs: { "id": "app" } },
     [
       _ c(
         'h1', { staticClass: "h1", staticStyle: { "color": "red" }, attrs: { "data-id": "1" } },
         [_v(_s(message))]
       )
     ]
   )
 }
}

正好符合JS的解析顺序。同时该方法会被缓存起来,下次有节点更新直接调用就好,一定程度上提高了页面渲染的性能。

2. Q:节点上的 v-onv-bind 等指令是什么时候绑定的

A:parseHTML 过程的 processAttrs 方法中


三、阅读源码后的一点感想

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

推荐阅读更多精彩内容