🧩 函数 1:oninterpolation(start, end)
oninterpolation(start, end) {
  if (inVPre) {
    return onText(getSlice(start, end), start, end)
  }
  let innerStart = start + tokenizer.delimiterOpen.length
  let innerEnd = end - tokenizer.delimiterClose.length
  while (isWhitespace(currentInput.charCodeAt(innerStart))) innerStart++
  while (isWhitespace(currentInput.charCodeAt(innerEnd - 1))) innerEnd--
  let exp = getSlice(innerStart, innerEnd)
  if (exp.includes('&')) {
    exp = __BROWSER__ ? currentOptions.decodeEntities!(exp, false) : decodeHTML(exp)
  }
  addNode({
    type: NodeTypes.INTERPOLATION,
    content: createExp(exp, false, getLoc(innerStart, innerEnd)),
    loc: getLoc(start, end),
  })
}
📖 功能说明
解析插值表达式 {{ ... }},生成 INTERPOLATION 节点。
🔍 拆解步骤
| 步骤 | 
描述 | 
| ① | 
若当前处于 v-pre 区域(跳过编译),则直接当作文本处理。 | 
| ② | 
计算插值内表达式的真实起止位置。 | 
| ③ | 
去除前后空白字符。 | 
| ④ | 
若表达式中包含 HTML 实体,则解码(如 < → <)。 | 
| ⑤ | 
调用 createExp() 构建表达式节点。 | 
| ⑥ | 
调用 addNode() 插入到当前父节点的 children 中。 | 
🧠 设计原理
createExp() 会尝试将 {{ message }} 转换为:
{
  "type": 5,
  "content": { "type": 4, "content": "message", "isStatic": false }
}
其中:
- NodeType 5 表示插值;
 
- NodeType 4 表示简单表达式。
 
🧩 函数 2:ondirname(start, end)
ondirname(start, end) {
  const raw = getSlice(start, end)
  const name =
    raw === '.' ? 'bind' :
    raw === ':' ? 'bind' :
    raw === '@' ? 'on' :
    raw === '#' ? 'slot' :
    raw.slice(2)
  ...
}
📖 功能说明
解析指令的名称部分,比如 v-if、v-for、v-bind、@click、:src。
🔍 拆解步骤
| 步骤 | 
内容 | 
| ① | 
从模板源中提取原始指令标识(v-、:、@ 等)。 | 
| ② | 
根据首字符映射到规范化名称: | 
- 
: → v-bind
 
- 
@ → v-on
 
- 
# → v-slot
 
- 
. → v-bind.prop |
| ③ | 若当前在 v-pre 模式或指令名为空,则退化为普通属性。 |
| ④ | 否则创建 DirectiveNode,初始化指令名、参数、修饰符数组。 |
| ⑤ | 特殊处理 v-pre:进入原样渲染模式,记录当前节点边界。 | 
📘 举例
<div :id="uid" @click="doSomething" v-if="ok"></div>
对应三个指令节点:
[  { "name": "bind", "arg": "id", "exp": "uid" },  { "name": "on", "arg": "click", "exp": "doSomething" },  { "name": "if", "exp": "ok" }]
🧩 函数 3:ondirarg(start, end)
ondirarg(start, end) {
  if (start === end) return
  const arg = getSlice(start, end)
  if (inVPre && !isVPre(currentProp!)) {
    (currentProp as AttributeNode).name += arg
    setLocEnd((currentProp as AttributeNode).nameLoc, end)
  } else {
    const isStatic = arg[0] !== `[`
    (currentProp as DirectiveNode).arg = createExp(
      isStatic ? arg : arg.slice(1, -1),
      isStatic,
      getLoc(start, end),
      isStatic ? ConstantTypes.CAN_STRINGIFY : ConstantTypes.NOT_CONSTANT,
    )
  }
}
📖 功能说明
解析指令参数,例如:
<div :id="foo"></div>
<div v-on:[event]="handler"></div>
中的 id 或 [event]。
🧠 原理
Vue 支持两种参数类型:
- 
静态参数:直接字符串,如 
:id; 
- 
动态参数:使用方括号包裹,如 
v-bind:[attr]。 
ondirarg 会判断是否为动态参数,并调用 createExp() 生成对应的表达式节点。
🧩 函数 4:ondirmodifier(start, end)
ondirmodifier(start, end) {
  const mod = getSlice(start, end)
  if (inVPre && !isVPre(currentProp!)) {
    (currentProp as AttributeNode).name += '.' + mod
    setLocEnd((currentProp as AttributeNode).nameLoc, end)
  } else if ((currentProp as DirectiveNode).name === 'slot') {
    const arg = (currentProp as DirectiveNode).arg
    if (arg) {
      (arg as SimpleExpressionNode).content += '.' + mod
      setLocEnd(arg.loc, end)
    }
  } else {
    const exp = createSimpleExpression(mod, true, getLoc(start, end))
    (currentProp as DirectiveNode).modifiers.push(exp)
  }
}
📖 功能说明
解析指令修饰符(如 .stop、.sync、.prevent 等)。
🔍 举例
<button @click.stop.prevent="doSomething"></button>
生成:
{
  "name": "on",
  "arg": "click",
  "modifiers": ["stop", "prevent"]
}
💡 特殊情况
v-slot 指令的修饰符实际是作用在参数上的,因此需要特殊拼接处理。
🧩 函数 5:onattribname(start, end)
onattribname(start, end) {
  currentProp = {
    type: NodeTypes.ATTRIBUTE,
    name: getSlice(start, end),
    nameLoc: getLoc(start, end),
    value: undefined,
    loc: getLoc(start),
  }
}
📖 功能说明
解析普通属性名(非指令),如:
<img src="logo.png" alt="Logo">
生成:
{ "type": "ATTRIBUTE", "name": "src", "value": "logo.png" }
🧩 函数 6:onattribdata(start, end) 与 onattribend(quote, end)
(a)onattribdata
onattribdata(start, end) {
  currentAttrValue += getSlice(start, end)
  if (currentAttrStartIndex < 0) currentAttrStartIndex = start
  currentAttrEndIndex = end
}
逐步累积属性值(例如处理 src="lo...go.png" 时,分多次调用)。
(b)onattribend
onattribend(quote, end) {
  if (currentOpenTag && currentProp) {
    setLocEnd(currentProp.loc, end)
    if (quote !== QuoteType.NoValue) {
      if (__BROWSER__ && currentAttrValue.includes('&')) {
        currentAttrValue = currentOptions.decodeEntities!(currentAttrValue, true)
      }
      if (currentProp.type === NodeTypes.ATTRIBUTE) {
        if (currentProp.name === 'class') {
          currentAttrValue = condense(currentAttrValue).trim()
        }
        currentProp.value = {
          type: NodeTypes.TEXT,
          content: currentAttrValue,
          loc: getLoc(currentAttrStartIndex, currentAttrEndIndex)
        }
      } else {
        currentProp.exp = createExp(currentAttrValue, false, getLoc(currentAttrStartIndex, currentAttrEndIndex))
      }
    }
    currentOpenTag.props.push(currentProp)
  }
  currentAttrValue = ''
  currentAttrStartIndex = currentAttrEndIndex = -1
}
📖 功能说明
当属性或指令值结束时被调用,用于创建 value 节点或指令表达式。
💡 特殊逻辑
- 对 
class 属性做空格压缩; 
- 对空值发出错误提示;
 
- 对 
v-for、v-on 等指令调用 createExp() 生成 Babel AST; 
- 检查 
.sync 修饰符以兼容 Vue 2。 
🧩 函数 7:oncomment(start, end)
oncomment(start, end) {
  if (currentOptions.comments) {
    addNode({
      type: NodeTypes.COMMENT,
      content: getSlice(start, end),
      loc: getLoc(start - 4, end + 3),
    })
  }
}
📖 功能说明
解析注释节点(<!-- comment -->),在启用 comments: true 时保留。
🧩 函数 8:ondir* 系列小结
| 函数 | 
作用 | 
典型输入 | 
输出类型 | 
ondirname | 
解析指令名 | 
v-if、:、@
 | 
DirectiveNode | 
ondirarg | 
解析参数 | 
[attr]、click
 | 
SimpleExpressionNode | 
ondirmodifier | 
解析修饰符 | 
.stop、.sync
 | 
数组元素 | 
onattribname | 
解析属性名 | 
class、src
 | 
AttributeNode | 
onattribend | 
解析属性值 | 
"foo" | 
TextNode or ExpressionNode
 | 
✅ 本章总结
这一章展示了 Vue 模板解析器最关键的部分——语法语义识别:
- 通过回调组合,实现类 HTML 语法的“增量解析”;
 
- 支持动态参数、修饰符与内嵌表达式;
 
- 自动区分指令与普通属性;
 
- 兼容 Vue 2.x 行为。
 
Vue 的模板语法并不是简单的 HTML 扩展,而是通过词法状态机 + 指令语义层的组合机制精确实现的。
📘 下一章预告(第四章)
我们将讲解更底层的表达式与循环结构解析逻辑,包括:
- 
parseForExpression()(v-for 拆解) 
- 
createExp()(表达式 AST 生成) 
- 
dirToAttr()(指令转属性) 
- 
isComponent()、isFragmentTemplate()(组件识别)