过滤器是纯函数,输入确定则输出确定;v-if不支持过滤器因只接受布尔表达式;小程序不支持自定义过滤器;条件判断应前置到调用侧或用计算属性替代。

过滤器本身不支持“根据条件动态返回不同内容”这种写法——它只是纯函数,输入确定,输出就确定。所谓“动态”,其实是把条件判断逻辑提前到调用侧,而不是塞进过滤器里。
为什么v-if里不能用过滤器做条件判断
因为v-if只接收 JavaScript 布尔表达式,而{{ value | filter }}是模板语法,编译器根本不允许它出现在指令绑定值中。你写v-if="{{ item.status | statusText }} === '已支付'",会直接报Invalid expression,连编译都过不去。
更关键的是:小程序平台压根不支持自定义过滤器,哪怕 H5 能跑通,一上真机就静默失效,控制台还不会报错。
- 过滤器只在
{{ }}和v-bind中生效,v-if、v-for、@click等指令都不走过滤器管道 - 试图在过滤器内部写
if/else判断状态并返回不同字符串是可以的,但前提是这个判断依据必须作为参数传进来,不能依赖外部响应式数据 - 如果过滤器里偷偷读
this.xxx或调用uni.getStorageSync,那它就不是纯函数,跨平台时极易出错
filter函数里怎么安全地做条件分支
可以,但必须把所有判断依据显式传入,比如状态码、枚举值、开关标志等。不要在过滤器里访问this、store或uni API。
示例:一个根据type返回不同文案的过滤器
// 全局注册(main.js)
Vue.filter('statusText', (type, mode = 'label') => {
const map = {
1: { label: '待付款', badge: 'primary' },
2: { label: '已发货', badge: 'success' },
3: { label: '已完成', badge: 'default' }
}
return map[type]?.[mode] || ''
})
模板中调用:
{{ item.type | statusText('label') }}
<view :class="'badge-' + (item.type | statusText('badge'))"></view>
- 第二个参数
mode必须是字面量或data里的响应式字段,不能是表达式如item.isDetail ? 'badge' : 'label' - 返回
undefined时,后续链式过滤器会收到undefined,可能引发Cannot read property 'xxx' of undefined - 如果
type来自接口且可能为null,建议在过滤器开头加if (!type) return ''
比过滤器更可靠的做法:用计算属性或方法封装条件逻辑
真正需要“根据条件返回不同内容”的场景,比如权限控制文案、多语言状态映射、状态图标颜色,都应该从模板层移出去,放到computed或methods里。
例如,要根据用户角色和订单状态组合显示不同按钮文案:
computed: {
actionText() {
if (this.role === 'admin') return '强制完成'
if (this.item.status === 1) return '去付款'
if (this.item.status === 2) return '查看物流'
return '查看详情'
}
}
然后模板里直接用{{ actionText }},清晰、可测试、三端一致。
- 计算属性能响应
this.role和this.item.status变化,过滤器做不到 - 方法调用如
{{ getActionText(role, item.status) }}也行,但注意避免在v-for里高频调用复杂逻辑 - 如果逻辑复用频繁,建议抽成工具函数,再在
computed或methods里调用,别硬塞进过滤器
最常被忽略的一点:过滤器没有缓存机制,每次渲染都重新执行。哪怕只是简单拼字符串,只要它在v-for里被调用上百次,性能损耗就比一个计算属性高得多。










