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() 判断)。
对两种类型的节点进行处理:
- 插值表达式(如
{{ msg | upper }}) - 指令表达式(如
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)
}
}
}
}
思路讲解:
- 简单表达式(如
msg | upper)直接进入下一步解析。 - 复合表达式(如
msg + "!" | wrap)则递归展开所有子节点,逐层扫描是否存在过滤器语法。 - 这种递归保证了在任意嵌套层级的表达式中都能正确识别过滤器。
四、核心逻辑: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}`
}
}
功能说明:
- 检查过滤器是否带参数(例如
truncate(10))。 - 调用
toValidAssetId()将过滤器名转为合法标识符。 - 将原表达式
exp作为第一个参数注入。 - 返回新的函数调用字符串。
六、对比:Vue 2 与 Vue 3 的不同
| 特性 | Vue 2 | Vue 3(兼容模式) | Vue 3(标准模式) |
|---|---|---|---|
| 过滤器语法 | 支持 ` | ` | 支持(内部转换) |
| 编译时行为 | 直接编译为 _f("filterName")(exp) | 重写为函数调用 | 不处理 |
| 性能影响 | 中等 | 低(仅兼容模式触发) | 无 |
七、实践示例
// 输入模板
{{ message | capitalize | append('!') }}
// 编译后表达式
_append(
_capitalize(message),
'!'
)
解释:
编译器会把 | 链式调用转换为多层函数嵌套调用,保持与 Vue 2 的行为一致。
八、拓展与启发
这个模块虽然只是为兼容而存在,但它体现了 Vue 编译器的几个关键思想:
- 语法兼容通过 AST 转换实现,而非运行时兼容。
- 通过状态机扫描避免误判字符。
- 函数式封装(wrapFilter)保持代码纯净与扩展性。
九、潜在问题与注意事项
- 性能开销:每个表达式都要字符级扫描,模板过大会影响编译性能。
- 语法歧义:若表达式中本身含
|(非过滤器用途),可能被误判。 - 未来弃用:Vue 3 官方已声明
filter将在未来版本完全移除,开发者应尽早改用 计算属性或方法替代。
结语:
transformFilter 是 Vue 3 兼容模式中的一个“桥梁模块”,它让旧项目无需改动即可运行在新架构上,同时展示了 Vue 编译器在语法转换上的高灵活性。
以上就是Vue编译器中的过滤器转换机制(transformFilter)详解的详细内容,更多关于Vue过滤器转换机制的资料请关注脚本之家其它相关文章!
