第 82 期 - Vue3 中 v - if 指令的模版编译解析
摘要
本文以 Vue3 中的 v - if 指令为例,阐述了模版编译过程,包括代码转换、generate 阶段、transform 阶段、baseParse 生成 AST 等内容,展示了如生成三目表达式等关键操作及相关节点属性的处理。
一、代码转换示例
在 Vue3 的 v - if 指令相关的模版编译中,首先给出了一个代码转换的例子。例如有这样的 Vue 模版:
<div id="app">
<h1 v - if="title">我是 A</h1>
<p v - else>我是 B</p>
</div>
它最终转换后的代码如下:
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("div", _hoisted_1, [
(_ctx.title)
? (_openBlock(), _createElementBlock("h1", _hoisted_2, "我是 A"))
: (_openBlock(), _createElementBlock("p", _hoisted_3, "我是 B"))
]));
}
二、generate 阶段
- 生成条件表达式语句
- 在 generate 阶段,根据 AST 节点类型(如果是 js 条件表达式即 JS_CONDITIONAL_EXPRESSION 类型),会调用
genConditionalExpression
来生成条件表达式语句。 - 在
genConditionalExpression
函数中,首先从节点获取关键属性如consequent
、alternate
等。如果测试表达式(test
)类型是简单表达式(SIMPLE_EXPRESSION
),会做相应处理,如判断是否需要括号等操作并调用genExpression
生成简单表达式;否则处理节点的其他情况。 - 在处理条件分支时,会解析
consequent
和alternate
属性,分别调用genNode
生成相应的表达式。
- 在 generate 阶段,根据 AST 节点类型(如果是 js 条件表达式即 JS_CONDITIONAL_EXPRESSION 类型),会调用
三、transform 阶段
- 基于 AST 的转换内容
- 在
transform
阶段,基于baseParse
阶段生成的 AST,并扩展了 AST 节点属性和指令节点的转换。这里的转换内容包含很多语法和指令相关的操作,语法方面如transformOnce
、transformIf
等,指令方面如transformOn
、transformBind
等。
- 在
- 处理 v - if 相关语法
- 当判断语法中有
if
时,会将之前生产的 JS AST 创建branch
节点属性,组装新的ifNode
来替换原有的节点。 - 如果是
v - else
语法,会移除该节点并生成branch
节点属性,赋值到兄弟节点的branchs
属性上。 - 在处理
v - if
语法时,能识别if | else | else - if
,会替换v - if
的节点并且生成对应的node
中的codegenNode
属性,在codegenNode
属性下追加alternate
属性。 - 调用
createCodegenNodeForBranch
后生成的节点数据结构包含consequent
、alternate
等属性。
- 当判断语法中有
四、baseParse 生成 AST
- 生成的 AST 初始状态
- 在
parse
阶段生成的 AST,对比babel AST
仅仅扩展了components
、dectives
等相关属性,还没有codegenNode
、branches
等节点属性。并且给出了一个示例的 AST 结构,包含type
、source
、children
等众多属性的详细信息。
- 在
Made by 捣鼓键盘的小麦 / © 2025 Front Talk 版权所有