parse
函数主要负责,将 template
模板转化为 AST
结构。
每个模块都专注于特定的功能,它们协同工作来完成模板到 AST
的转换过程。
这种模块化的设计使得代码更容易维护和理解,同时也方便针对特定功能进行优化或扩展。
1. 核心解析模块
解析器分为以下 3
种:
parseHTML
parseText
parseFilters
js
export function parse(template: string, options: CompilerOptions): ASTElement {
// 初始化配置
warn = options.warn || baseWarn
platformIsPreTag = options.isPreTag || no
// ... 其他配置
// 解析模板
parseHTML(template, {
start(...) { /* 处理开始标签 */ },
end(...) { /* 处理结束标签 */ },
chars(...) { /* 处理文本内容 */ },
comment(...) { /* 处理注释 */ }
})
}
TIP
parseText
识别并解析0
parseFilters
解析:title="message | capitalize"
中的message | capitalize
表达式- 生成最终的渲染代码:
_f("capitalize")(_s(message))
2. 指令处理模块
- v-for 处理
js
function processFor(el) {
// 解析 v-for 指令
// 处理 "(item, index) in items" 格式
}
function parseFor(exp: string) {
// 解析 v-for 表达式
// 返回 { for, alias, iterator1, iterator2 } 结构
}
- v-if 处理
js
function processIf(el) {
// 处理 v-if/v-else/v-else-if
// 管理条件渲染链
}
function processIfConditions(el, parent) {
// 处理条件之间的关系
}
- 插槽处理
js
function processSlotContent(el) {
// 处理 slot-scope 和 v-slot
// 处理具名插槽和默认插槽
}
function processSlotOutlet(el) {
// 处理 <slot> 组件
}
关于插槽的额外补充,需要牢记一句话:插槽是解析在父组件作用域,但渲染在子组件作用域的虚拟Node节点。
假设有如下 template
结构:
html
<template>
<div>
<HelloWorld>
<template v-slot:default>123</template>
<template v-slot:scope="slotScope">
{{ slotScope }}
</template>
</HelloWorld>
</div>
</template>
解析之后的 AST
结构如下:
3. 属性处理模块
- 属性解析
js
function processAttrs(el) {
// 处理元素的所有属性
// 区分普通属性和指令
// 处理绑定和事件
}
function processKey(el) {
// 处理 key 属性
}
function processRef(el) {
// 处理 ref 属性
}
- 修饰符处理
js
function parseModifiers(name: string) {
// 解析属性/事件的修饰符
// 如 .prevent, .stop 等
}
4. 组件处理模块
js
function processComponent(el) {
// 处理组件相关属性
// 处理 is 属性
// 处理内联模板
}
5. 特殊属性处理模块
- 原始属性处理
js
function processRawAttrs(el) {
// 处理 v-pre 内的属性
// 保持属性原始状态
}
- 预处理属性
js
function processPre(el) {
// 处理 v-pre 指令
}
6. 工具函数模块
- 属性映射
js
function makeAttrsMap(attrs: Array<Record<string, any>>) {
// 将属性数组转换为映射对象
}
- 元素类型判断
js
function isTextTag(el) {
// 判断是否是文本标签
}
function isForbiddenTag(el) {
// 判断是否是禁止的标签
}
- 空白处理
js
function trimEndingWhitespace(el) {
// 处理元素末尾的空白节点
}
7. 错误检查模块
js
function checkRootConstraints(el) {
// 检查根元素约束
}
function checkForAliasModel(el, value) {
// 检查 v-model 与 v-for 别名冲突
}
8. 浏览器兼容模块
js
function guardIESVGBug(attrs) {
// 处理 IE SVG 命名空间问题
}