第 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等众多属性的详细信息。
- 在
