Vue 模板编译原理
概述
Vue 的模板编译将 template 转换为 render 函数,分为三个阶段:解析(parse)、转换(transform)、生成(generate)。
一、编译流程
Template String → Parse → AST → Transform → 优化AST → Generate → Render Function二、解析阶段 (Parse)
AST 节点类型
typescript
interface ElementNode {
type: 'Element';
tag: string;
props: Array<AttributeNode | DirectiveNode>;
children: TemplateChildNode[];
}
interface InterpolationNode {
type: 'Interpolation';
content: ExpressionNode;
}示例
javascript
const template = '<div><p>{{ msg }}</p></div>';
// AST
{
type: 'Root',
children: [{
type: 'Element',
tag: 'div',
children: [{
type: 'Element',
tag: 'p',
children: [{
type: 'Interpolation',
content: { content: 'msg' }
}]
}]
}]
}三、转换阶段 (Transform)
转换目的
- 语法糖展开: v-if/v-for/v-model
- 静态分析: 标记静态节点
- 优化标记: 添加 PatchFlag
静态提升分析
javascript
function isStaticNode(node) {
return !node.props.some(p => p.type === 'Directive') &&
node.children.every(isStaticNode);
}四、生成阶段 (Generate)
javascript
// 模板
<div id="app"><p>{{ msg }}</p></div>
// 生成的 render 函数
function render(_ctx) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("p", null, _toDisplayString(_ctx.msg), 1)
]))
}五、指令编译
v-model
javascript
// <input v-model="text" />
_createVNode("input", {
modelValue: _ctx.text,
"onUpdate:modelValue": $event => (_ctx.text = $event)
})v-on
javascript
// <button @click.stop="handleClick">
_createVNode("button", {
onClick: _withModifiers(_ctx.handleClick, ["stop"])
})六、编译优化
- 静态提升: 静态节点只创建一次
- 事件缓存: 避免重复创建事件函数
- PatchFlag: 标记动态内容类型
面试高频题
Q1: 模板编译三个阶段?
Parse(解析) → Transform(转换) → Generate(生成)
Q2: 静态提升原理?
将静态 VNode 创建提升到 render 外,多次渲染复用。
Q3: v-if 和 v-for 不能一起用?
Vue 3 中 v-if 优先级更高,但此时 v-for 变量未定义。