本页面将介绍 Vue.js 如何将模板代码编译为渲染函数,重点关注从 HTML 模板到可执行 JavaScript 的内部转换流程。有关单文件组件(SFC)编译的信息,请参阅 SFC 编译。
Vue 的模板编译器将 Vue 模板语法转换为高度优化的渲染函数,用于创建虚拟 DOM 节点。此编译是一个多阶段过程,涉及解析、转换和代码生成。
Vue 中的模板编译过程可分为三个主要阶段:
来源
流程中的每个组件都有特定的作用:
解析器接收模板字符串并将其转换为抽象语法树 (AST),这是模板的结构化表示。
来源
AST 包含不同类型的节点,每种节点代表模板的特定部分:
| 节点类型 | 描述 | 示例 |
|---|---|---|
| 元素 | HTML 或组件元素 | <div>, <MyComponent> |
| 文本 | 静态文本内容 | Hello World |
| 插值 | 动态表达式 | {{ name }} |
| 注释 | HTML 注释 | <!-- comment --> |
| 复合表达式 | 混合静态/动态内容 | Hello ${name}! |
| 指令 | Vue 指令 | v-if, v-for, v-bind |
来源
解析完成后,AST 会经历一系列转换,为代码生成做好准备。
来源
转换过程使用一个转换上下文,其中包含:
元素转换 (Element Transform):处理元素并生成 VNode 创建代码。
指令转换 (Directive Transforms):将 Vue 指令转换为 props 或运行时指令。
结构转换 (Structure Transforms):处理结构性指令。
优化转换:
来源
最后一个阶段是从转换后的 AST 生成 JavaScript 代码。
来源
代码生成器可以输出不同模式的代码:
| 模式 | 描述 | 示例 |
|---|---|---|
| 函数模式 (Function Mode) | 生成使用 Vue 全局的函数。 | function render(_ctx, _cache) {...} |
| 模块模式 (Module Mode) | 生成带有导入的模块。 | import { createVNode } from "vue"; export function render(...) {...} |
来源
此图显示了主要的内部组件及其关系。
来源
元素转换是编译过程中最重要的部分之一,因为它决定了元素如何转换为 VNode 调用。
来源
标签解析 (Tag Resolution):
is prop 或 <component> 标签)。Props 处理:
子节点处理:
Patch Flag 确定:
VNode 调用创建:
来源
模板编译器包含多种优化技术,以提高运行时性能:
不会改变的静态内容会被提升出渲染函数,以避免在每次渲染时重新创建。
每个 VNode 都会标记上指示哪些部分可能更改的 flags,这使得运行时可以跳过静态部分的 diff。
| 标志 | 描述 |
|---|---|
| TEXT | 文本内容可能发生变化。 |
| CLASS | Class 绑定可能发生变化。 |
| STYLE | Style 绑定可能发生变化。 |
| PROPS | 某些 props 可能发生变化。 |
| FULL_PROPS | Props 需要完全 diff。 |
| HYDRATE_EVENTS | 包含 hydration 事件监听器。 |
| STABLE_FRAGMENT | 内容稳定的 Fragment。 |
| KEYED_FRAGMENT | 带有 key 的子节点的 Fragment。 |
| UNKEYED_FRAGMENT | 没有 key 的子节点的 Fragment。 |
需要完全 diff 的元素会创建 "block",用于跟踪动态节点,从而使运行时能够跳过静态子树的遍历。
来源
编译后的渲染函数与 Vue 的运行时系统集成。
来源
编译器生成对从 Vue 导入的运行时辅助函数的引用。
| 辅助函数 | 描述 |
|---|---|
| createVNode | 创建虚拟节点。 |
| createElementVNode | 创建带有优化的元素 vnode。 |
| createElementBlock | 创建用于优化更新的 block 元素。 |
| createTextVNode | 创建文本 vnode。 |
| createCommentVNode | 创建注释 vnode。 |
| toDisplayString | 将值转换为显示字符串。 |
| resolveComponent | 在运行时解析组件。 |
| resolveDirective | 在运行时解析指令。 |
| renderList | 渲染项目列表。 |
| withDirectives | 将指令应用于 vnode。 |
| openBlock | 打开一个新 block 以进行优化更新。 |
来源
Vue 的模板编译是一个复杂的过程,它将模板转换为高度优化的渲染函数。编译器应用各种优化来最大限度地减少初始渲染成本和后续更新成本。
要点
这个编译过程是 Vue 响应式系统的关键部分,它使框架能够同时提供对开发者友好的模板和高性能的渲染。