每个元素都是一个节点。每片文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点 (也就是说每个部分可以包含其它的一些部分)。
HTML 的 DOM 节点树如下图所示:
高效的更新所有这些节点会是比较困难的,不过所幸你不必再手动完成这个工作了。你只需要告诉 Vue 你希望页面上的 HTML 是什么,这可以是在一个模板里:
或者一个渲染函数里:
在这两种情况下,Vue 都会自动保持页面的更新,即便 blogTitle 发生了改变。
虚拟DOM
Vue 通过建立一个虚拟 DOM 对真实 DOM 发生的变化保持追踪。请近距离看一下这行代码:
createElement
到底会返回什么呢?其实不是一个实际的 DOM 元素。它更准确的名字可能是 createNodeDescription
,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,及其子节点。我们把这样的节点描述为“虚拟节点 (Virtual Node)”,也常简写它为“VNode”。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。
createElement 参数
接下来你需要熟悉的是如何在 createElement 函数中生成模板。这里是 createElement 接受的参数:
|
|
深入 data 对象
有一件事要注意:正如在模板语法中,v-bind:class 和 v-bind:style ,会被特别对待一样,在 VNode 数据对象中,下列属性名是级别最高的字段。该对象也允许你绑定普通的 HTML 特性,就像 DOM 属性一样,比如 innerHTML (这会取代 v-html 指令)。
|
|
完整示例
|
|
约束
VNodes 必须唯一
组件树中的所有 VNodes 必须是唯一的。这意味着,下面的 render function 是无效的:
如果你真的需要重复很多次的元素/组件,你可以使用工厂函数来实现。例如,下面这个例子 render 函数完美有效地渲染了 20 个重复的段落:
|
|
使用 JavaScript 代替模板功能
v-if 和 v-for
由于使用原生的 JavaScript 来实现某些东西很简单,Vue 的 render 函数没有提供专用的 API。比如,template 中的 v-if 和 v-for:
|
|
这些都会在 render 函数中被 JavaScript 的 if/else 和 map 重写:
v-model
render 函数中没有与 v-model 相应的 api - 你必须自己来实现相应的逻辑:
|
|
这就是深入底层要付出的,尽管麻烦了一些,但相对于 v-model 来说,你可以更灵活地控制。
事件 & 按键修饰符
对于 .passive、.capture 和 .once事件修饰符, Vue 提供了相应的前缀可以用于on
插槽
你可以从 this.$slots
获取 VNodes 列表中的静态内容:
|
|
还可以从 this.$scopedSlots 中获得能用作函数的作用域插槽,这个函数返回 VNodes:
|
|
如果要用渲染函数向子组件中传递作用域插槽,可以利用 VNode 数据中的 scopedSlots
|
|