vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue过滤器转换机制

Vue编译器中的过滤器转换机制(transformFilter)详解

作者:excel

本文将详细解读 Vue 兼容模式下的过滤器编译逻辑——transformFilter 模块,它是 Vue 3 为了兼容 Vue 2 模板过滤器语法而存在的编译阶段转换器,需要的朋友可以参考下

一、背景:为什么需要 transformFilter?

在 Vue 2 中,我们可以写出这样的模板:

{{ message | capitalize }}

过滤器(Filter)语法允许开发者在模板中使用管道符(|)对数据进行格式化。

但在 Vue 3 中,这个语法被移除了,因为它让模板逻辑与展示层混杂,不利于维护。

为了让旧项目平滑迁移到 Vue 3,官方在“兼容模式(compat mode) ”中保留了该特性,而 transformFilter 就是负责 在编译时| 表达式“翻译”为函数调用的核心逻辑。

二、入口函数:transformFilter()

export const transformFilter: NodeTransform = (node, context) => {
  if (!isCompatEnabled(CompilerDeprecationTypes.COMPILER_FILTERS, context)) {
    return
  }

  if (node.type === NodeTypes.INTERPOLATION) {
    rewriteFilter(node.content, context)
  } else if (node.type === NodeTypes.ELEMENT) {
    node.props.forEach((prop) => {
      if (
        prop.type === NodeTypes.DIRECTIVE &&
        prop.name !== 'for' &&
        prop.exp
      ) {
        rewriteFilter(prop.exp, context)
      }
    })
  }
}

作用解析:

仅在兼容模式下生效(通过 isCompatEnabled() 判断)。

对两种类型的节点进行处理:

  1. 插值表达式(如 {{ msg | upper }}
  2. 指令表达式(如 v-bind:title="msg | trim"

每个匹配到的表达式都会交给 rewriteFilter() 进行进一步分析。

三、递归分析:rewriteFilter()

function rewriteFilter(node: ExpressionNode, context: TransformContext) {
  if (node.type === NodeTypes.SIMPLE_EXPRESSION) {
    parseFilter(node, context)
  } else {
    for (let child of node.children) {
      if (typeof child !== 'object') continue
      if (child.type === NodeTypes.SIMPLE_EXPRESSION) {
        parseFilter(child, context)
      } else if (child.type === NodeTypes.COMPOUND_EXPRESSION) {
        rewriteFilter(node, context)
      } else if (child.type === NodeTypes.INTERPOLATION) {
        rewriteFilter(child.content, context)
      }
    }
  }
}

思路讲解:

四、核心逻辑:parseFilter()

function parseFilter(node: SimpleExpressionNode, context: TransformContext) {
  const exp = node.content
  let inSingle = false, inDouble = false, inTemplateString = false
  let inRegex = false
  let curly = 0, square = 0, paren = 0
  let lastFilterIndex = 0
  let expression, filters: string[] = []

  for (let i = 0; i < exp.length; i++) {
    const c = exp.charCodeAt(i)
    ...
    if (c === 0x7c && !curly && !square && !paren) {
      if (expression === undefined) {
        lastFilterIndex = i + 1
        expression = exp.slice(0, i).trim()
      } else {
        pushFilter()
      }
    }
  }

  if (expression === undefined) {
    expression = exp.trim()
  } else if (lastFilterIndex !== 0) {
    pushFilter()
  }

  if (filters.length) {
    for (let f of filters) {
      expression = wrapFilter(expression, f, context)
    }
    node.content = expression
  }
}

关键逻辑说明:

状态机扫描
遍历表达式的每个字符,记录当前是否处于:

识别管道符
当遇到顶层 |(非 ||),并且不在任何括号中时,认为是一个过滤器的起点。

拆分表达式与过滤器
message | capitalize | trim(10) 拆为:

expression = "message"
filters = ["capitalize", "trim(10)"]

重组表达式
通过 wrapFilter() 将过滤器按从左到右顺序包装成嵌套调用:

toValidAssetId('capitalize', 'filter')(
  toValidAssetId('trim', 'filter')(message)
)

五、封装函数:wrapFilter()

function wrapFilter(exp: string, filter: string, context: TransformContext) {
  context.helper(RESOLVE_FILTER)
  const i = filter.indexOf('(')
  if (i < 0) {
    context.filters!.add(filter)
    return `${toValidAssetId(filter, 'filter')}(${exp})`
  } else {
    const name = filter.slice(0, i)
    const args = filter.slice(i + 1)
    context.filters!.add(name)
    return `${toValidAssetId(name, 'filter')}(${exp}${args !== ')' ? ',' + args : args}`
  }
}

功能说明:

六、对比:Vue 2 与 Vue 3 的不同

特性Vue 2Vue 3(兼容模式)Vue 3(标准模式)
过滤器语法支持 ``支持(内部转换)
编译时行为直接编译为 _f("filterName")(exp)重写为函数调用不处理
性能影响中等低(仅兼容模式触发)

七、实践示例

// 输入模板
{{ message | capitalize | append('!') }}

// 编译后表达式
_append(
  _capitalize(message),
  '!'
)

解释:
编译器会把 | 链式调用转换为多层函数嵌套调用,保持与 Vue 2 的行为一致。

八、拓展与启发

这个模块虽然只是为兼容而存在,但它体现了 Vue 编译器的几个关键思想:

  1. 语法兼容通过 AST 转换实现,而非运行时兼容。
  2. 通过状态机扫描避免误判字符。
  3. 函数式封装(wrapFilter)保持代码纯净与扩展性。

九、潜在问题与注意事项

结语:

transformFilter 是 Vue 3 兼容模式中的一个“桥梁模块”,它让旧项目无需改动即可运行在新架构上,同时展示了 Vue 编译器在语法转换上的高灵活性。

以上就是Vue编译器中的过滤器转换机制(transformFilter)详解的详细内容,更多关于Vue过滤器转换机制的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文