Skip to content

parse 函数主要负责,将 template 模板转化为 AST 结构。

每个模块都专注于特定的功能,它们协同工作来完成模板到 AST 的转换过程。

这种模块化的设计使得代码更容易维护和理解,同时也方便针对特定功能进行优化或扩展。

1. 核心解析模块

解析器分为以下 3 种:

  1. parseHTML
  2. parseText
  3. 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

  1. parseText 识别并解析 0
  2. parseFilters 解析 :title="message | capitalize" 中的 message | capitalize 表达式
  3. 生成最终的渲染代码:_f("capitalize")(_s(message))

2. 指令处理模块

  1. v-for 处理
js
function processFor(el) {
  // 解析 v-for 指令
  // 处理 "(item, index) in items" 格式
}

function parseFor(exp: string) {
  // 解析 v-for 表达式
  // 返回 { for, alias, iterator1, iterator2 } 结构
}
  1. v-if 处理
js
function processIf(el) {
  // 处理 v-if/v-else/v-else-if
  // 管理条件渲染链
}

function processIfConditions(el, parent) {
  // 处理条件之间的关系
}
  1. 插槽处理
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. 属性处理模块

  1. 属性解析
js
function processAttrs(el) {
  // 处理元素的所有属性
  // 区分普通属性和指令
  // 处理绑定和事件
}

function processKey(el) {
  // 处理 key 属性
}

function processRef(el) {
  // 处理 ref 属性
}
  1. 修饰符处理
js
function parseModifiers(name: string) {
  // 解析属性/事件的修饰符
  // 如 .prevent, .stop 等
}

4. 组件处理模块

js
function processComponent(el) {
  // 处理组件相关属性
  // 处理 is 属性
  // 处理内联模板
}

5. 特殊属性处理模块

  1. 原始属性处理
js
function processRawAttrs(el) {
  // 处理 v-pre 内的属性
  // 保持属性原始状态
}
  1. 预处理属性
js
function processPre(el) {
  // 处理 v-pre 指令
}

6. 工具函数模块

  1. 属性映射
js
function makeAttrsMap(attrs: Array<Record<string, any>>) {
  // 将属性数组转换为映射对象
}
  1. 元素类型判断
js
function isTextTag(el) {
  // 判断是否是文本标签
}

function isForbiddenTag(el) {
  // 判断是否是禁止的标签
}
  1. 空白处理
js
function trimEndingWhitespace(el) {
  // 处理元素末尾的空白节点
}

7. 错误检查模块

js
function checkRootConstraints(el) {
  // 检查根元素约束
}

function checkForAliasModel(el, value) {
  // 检查 v-model 与 v-for 别名冲突
}

8. 浏览器兼容模块

js
function guardIESVGBug(attrs) {
  // 处理 IE SVG 命名空间问题
}