Vue -- VFor的编译处理

Published: · LastMod: April 07, 2024 · 690 words

vue – VFor的编译处理 🔗

“version”: “3.2.37”

createStructuralDirectiveTransform 🔗

通用函数, 根据模板创建指令数据,匹配对应的名字或者正则

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
export function createStructuralDirectiveTransform(
  name: string | RegExp,
  fn: StructuralDirectiveTransform
): NodeTransform {
  // 闭包函数,返回一个匹配函数
  const matches = isString(name)
    ? (n: string) => n === name
    : (n: string) => name.test(n)

  return (node, context) => {
    // node是元素节点
    if (node.type === NodeTypes.ELEMENT) {
      const { props } = node
      // structural directive transforms are not concerned with slots
      // as they are handled separately in vSlot.ts
      if (node.tagType === ElementTypes.TEMPLATE && props.some(isVSlot)) {
        return
      }
      // 遍历props
      const exitFns = []
      for (let i = 0; i < props.length; i++) {
        const prop = props[i]
        // 如果props的类型是指令,并且能够匹配到
        if (prop.type === NodeTypes.DIRECTIVE && matches(prop.name)) {
          // 在执行之前删除指定的指令,防止递归执行,移动相关的节点
          props.splice(i, 1)
          i--
          // 收集退出函数
          const onExit = fn(node, prop, context)
          if (onExit) exitFns.push(onExit)
        }
      }
      // 最终返回退出函数的队列
      return exitFns
    }
  }
}

processFor 🔗

处理for语句的相关代码

parseForExpression 🔗

解析for语句相关的代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
export function parseForExpression(
  input: SimpleExpressionNode,
  context: TransformContext
): ForParseResult | undefined {
  // 代码位置
  const loc = input.loc
  const exp = input.content
  // 根据template中for语句的代码正则匹配
  const inMatch = exp.match(forAliasRE)
  if (!inMatch) return
  // 拿到in/of左右两边的值
  const [, LHS, RHS] = inMatch

  // 创建出for语句返回结果
  const result: ForParseResult = {
    // 拿到左右两边的位置信息
    source: createAliasExpression(
      loc,
      RHS.trim(),
      exp.indexOf(RHS, LHS.length)
    ),
    value: undefined,
    key: undefined,
    index: undefined
  }
  if (!__BROWSER__ && context.prefixIdentifiers) {
    result.source = processExpression(
      result.source as SimpleExpressionNode,
      context
    )
  }


  let valueContent = LHS.trim().replace(stripParensRE, '').trim()
  const trimmedOffset = LHS.indexOf(valueContent)

  // 是否存在迭代相关的代码
  const iteratorMatch = valueContent.match(forIteratorRE)
  if (iteratorMatch) {
    valueContent = valueContent.replace(forIteratorRE, '').trim()

    const keyContent = iteratorMatch[1].trim()
    let keyOffset: number | undefined
    if (keyContent) {
      keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length)
      result.key = createAliasExpression(loc, keyContent, keyOffset)
      if (!__BROWSER__ && context.prefixIdentifiers) {
        result.key = processExpression(result.key, context, true)
      }
    }

    if (iteratorMatch[2]) {
      const indexContent = iteratorMatch[2].trim()

      if (indexContent) {
        result.index = createAliasExpression(
          loc,
          indexContent,
          exp.indexOf(
            indexContent,
            result.key
              ? keyOffset! + keyContent.length
              : trimmedOffset + valueContent.length
          )
        )
        if (!__BROWSER__ && context.prefixIdentifiers) {
          result.index = processExpression(result.index, context, true)
        }
        if (__DEV__ && __BROWSER__) {
          validateBrowserExpression(
            result.index as SimpleExpressionNode,
            context,
            true
          )
        }
      }
    }
  }

  if (valueContent) {
    result.value = createAliasExpression(loc, valueContent, trimmedOffset)
    if (!__BROWSER__ && context.prefixIdentifiers) {
      result.value = processExpression(result.value, context, true)
    }
  }
 
  return result
}