轻云听书app
17.87MB · 2025-10-15
当你写下:
<template>
<div class="title">{{ message }}</div>
</template>
Vue 内部究竟发生了什么?
本文将带你深入 Vue 编译器核心,揭秘 Template → AST → Render 函数 的完整链路。
Template (字符串)
↓
parse() → AST (抽象语法树)
↓
optimize() → 优化 AST(标记静态节点)
↓
generate() → Render 字符串
↓
new Function() → Render 函数
↓
执行 → VNode → DOM
parse
→ 生成 AST将模板字符串转换为 抽象语法树(AST),用 JavaScript 对象描述模板结构。
<div class="title" v-if="show">
Hello {{ name }}
<span>Static Text</span>
</div>
{
type: 1, // 元素节点
tag: 'div',
attrsList: [
{ name: 'class', value: 'title' },
{ name: 'v-if', value: 'show' }
],
children: [
{
type: 3, // 文本节点
text: 'Hello ',
static: false
},
{
type: 2, // 表达式节点
expression: '_s(name)',
text: '{{ name }}',
static: false
},
{
type: 1,
tag: 'span',
children: [
{ type: 3, text: 'Static Text', static: true }
],
static: true // 整个 span 是静态的
}
],
static: false,
staticRoot: false
}
parse
如何工作?<div>
→ 开始标签 → 执行 start()
回调;</div>
→ 结束标签 → 执行 end()
回调;Hello {{ name }}
→ 文本 → 执行 chars()
回调;optimize
→ 静态节点优化标记永不变化的节点,在后续更新中跳过 diff,极大提升性能。
节点类型 | 是否静态 | 判断依据 |
---|---|---|
<span>Static</span> | 纯文本,无绑定 | |
{{ message }} | 包含变量 | |
<div v-if="false"> | 指令依赖响应式数据 | |
<img src="./logo.png"> | 属性无绑定 |
{
tag: 'span',
static: true, // 标记为静态节点
staticRoot: true, // 标记为静态根(可提升)
children: [/* ... */]
}
patch
;generate
→ 生成 Render 函数代码将优化后的 AST 转换为可执行的 render
函数字符串。
with(this) {
return (show)
? _c('div', { staticClass: "title" }, [
_v("Hello " + _s(name)),
_c('span', [_v("Static Text")])
])
: _e()
}
函数 | 作用 | 源码对应 |
---|---|---|
_c | createElement | 创建 VNode |
_v | createTextVNode | 创建文本节点 |
_s | toString | 转换表达式 |
_e | createEmptyVNode | 创建空节点 |
generate
如何工作?_c(tag, data, children)
_v(text)
_s(expression)
v-if
→ 三元表达式;v-for
→ _l(array, function)
v-on
→ 事件监听对象const render = new Function(`with(this){return ${code}}`)
render
函数执行结果// 执行 render() 返回 VNode
{
tag: 'div',
data: { staticClass: 'title' },
children: [
{ text: 'Hello Vue', ... },
{ tag: 'span', children: [...], ... }
]
}
优化 | 说明 |
---|---|
静态提升 | 将静态节点提升到 render 外,只创建一次 |
Patch Flag | 动态节点打标记,diff 时只比对相关部分 |
Tree Shaking | 未使用的转换函数被摇除 |
import { createElementVNode as _createElementVNode } from 'vue'
const _hoisted_1 = /*#__PURE__*/ _createElementVNode("span", null, "Static Text", -1 /* HOISTED */)
return function render(_ctx, _cache) {
return (_ctx.show)
? (_openBlock(), _createElementVNode("div", { class: "title" }, [
_createTextVNode("Hello " + _toDisplayString(_ctx.name), 1 /* TEXT */),
_hoisted_1
], 64 /* STABLE_FRAGMENT */))
: _createEmptyVNode()
}
模式 | 编译时机 | 调试支持 |
---|---|---|
开发模式 | 运行时编译(vue.js) | 模板错误定位精确 |
生产模式 | 构建时编译(vue.runtime.js) | 体积小、性能高 |
阶段 | 输入 | 输出 | 目的 |
---|---|---|---|
parse | 模板字符串 | AST | 结构化描述 |
optimize | AST | 优化 AST | 标记静态内容 |
generate | 优化 AST | Render 字符串 | 生成可执行代码 |
掌握模板编译过程,你就能:
理解 {{ }}
和指令的底层原理;
优化模板结构提升性能;
调试编译错误更高效;
为学习 Vue 3 编译优化打下基础。