Vue2里的filters到底怎么用?一篇文章讲透常见问题
不少刚学Vue2的同学,面对filters总会犯懵——这玩意儿和computed、methods有啥不一样?怎么注册?能不能传参数?今天就借着8个常见问题,把Vue2 filters的用法、特点、场景这些事儿掰开揉碎讲清楚,新手也能轻松看懂~
Vue2 filters是干啥的?
简单说,filters是Vue2里专门用来做文本格式化的工具,打个比方:后端返回的时间是时间戳(比如1699999999999),咱要在页面上显示成“2023-11-12 10:00”这种友好格式;或者数字123要变成“¥123.00”这种金额样式——这些「把原始数据改成适合展示的样子」的操作,就可以交给filters。
它的用法很像“管道”:在模板里用 符号把「要处理的数据」和「过滤器函数」连起来,{{ timestamp | formatTime }}
,这里 timestamp
是要处理的原始数据,formatTime
是定义好的过滤器函数,执行后输出格式化后的结果。
注意哈,filters只负责“展示层”的格式化,不会修改原始数据,比如你过滤时间戳后,data里的timestamp还是原来的数字,只是页面上显示变了~
filters和computed、methods有啥区别?
很多同学刚开始分不清这仨,其实它们的设计目的、执行时机、使用场景都不一样,咱们逐个对比:
和computed比
computed(计算属性)是依赖缓存的——只有依赖的响应式数据变化时,才会重新计算,适合处理多个数据组合、有依赖关系的逻辑,比如购物车页面,“总价”依赖“商品数量”和“单价”,用computed写 totalPrice() { return this.count * this.price }
,只要count或price不变,totalPrice就不会重复计算,性能更优。
但filters不缓存,每次模板渲染都会执行(如果数据变化触发渲染的话),而且它只专注“格式化”,不像computed能处理复杂的业务逻辑组合。
和methods比
methods里的函数,每次组件渲染都会执行(不管数据变没变),适合做「事件处理」(比如点击按钮的回调),或者「不需要缓存、每次都要重新算」的逻辑,比如写个 handleClick() { ... }
给按钮绑定点击事件。
filters和methods有点像,但使用场景更窄——只能在模板里用(插值、指令里的表达式),而methods还能在JS代码里调用(比如生命周期钩子中调用this.handleClick()
),filters的参数规则更特殊(第一个参数固定是管道左边的数据),而methods传参更自由。
如果是纯展示用的格式化(比如时间、金额、字符串拼接),优先用filters;如果是多个数据的联动计算,用computed;如果是事件处理或无规律的函数调用,用methods~
filters怎么注册?全局和局部有啥不同?
Vue2里注册filters分局部注册和全局注册两种,用法和作用范围不一样:
局部注册:只给当前组件用
在组件的 filters
选项里写函数,比如处理金额:
export default { data() { return { price: 123 } }, filters: { formatPrice(value) { // value就是管道左边的price(123) return `¥${value.toFixed(2)}` // 输出 ¥123.00 } } }
然后在当前组件的模板里用 {{ price | formatPrice }}
,其他组件用不了这个过滤器~
全局注册:所有组件都能调用
在Vue实例创建前,用 Vue.filter('过滤器名', 函数)
注册,一般在项目的入口文件(比如main.js)里写:
import Vue from 'vue' import App from './App.vue' <p>// 全局注册formatTime过滤器 Vue.filter('formatTime', function(timestamp) { return new Date(timestamp).toLocaleDateString() })</p> <p>new Vue({ render: h => h(App) }).$mount('#app')
这样所有组件的模板里,都能直接用 {{ time | formatTime }}
啦~
两者区别
全局过滤器作用范围是所有组件,局部只有当前组件能用;如果全局和局部注册了同名过滤器,组件内优先用局部的(局部会覆盖全局)。
filters能传多个参数不?怎么传?
必须能!而且传参语法很灵活~ 管道左边的“数据”是第一个参数,后面括号里的都是你传的参数。
举个例子:想让时间格式化支持自定义格式(YYYY-MM-DD”或“HH:mm”),过滤器这么写:
filters: { formatTime(value, format = 'YYYY-MM-DD') { // value是管道左边的数据,format是传的参数,默认值选填 return dayjs(value).format(format) // 假设用dayjs库处理时间 } }
模板里调用时,传参数进去:
<!-- 只传数据,用默认格式 --> {{ time | formatTime }} <p><!-- 传自定义格式 --> {{ time | formatTime('HH:mm:ss') }}
这里 value
接收的是 time
,format
接收的是 'HH:mm:ss'
,要是需要传多个参数,括号里逗号分隔就行,formatTime('参数1', '参数2')
,过滤器函数里对应写 (value, arg1, arg2)
~
多个filters能串联使用吗?
必须能!而且特别适合多步骤格式化的场景,语法是从左到右依次执行:{{ 数据 | 过滤器A | 过滤器B }}
——数据先经过过滤器A处理,输出的结果再交给过滤器B处理。
举个实际例子:把数字先转成金额格式(加¥),再转成红色样式(包一层span标签)。
filters: { addYuan(value) { // 第一步:加¥ return `¥${value.toFixed(2)}` }, addRedStyle(value) { // 第二步:加红色样式 return `<span style="color:red;">${value}</span>` } }
模板里串联使用:
<!-- 先执行addYuan,再执行addRedStyle --> {{ 123 | addYuan | addRedStyle }}
最终输出 <span style="color:red;">¥123.00</span>
(注意:如果要渲染HTML,得用 v-html
指令,否则会当字符串显示~)
提醒一下:前一个过滤器的输出,必须能被后一个过滤器接收,比如过滤器A返回数字,过滤器B却要处理字符串,就会报错,所以串联时要保证数据格式能“衔接上”~
filters只能用在插值{{ }}里吗?指令和v-bind能用不?
不止插值!只要是模板里的JS表达式,都能放过滤器,常见场景有这几个:
v-bind指令里的属性值
比如给图片链接加域名前缀:
<!-- 假设imageUrl是'/logo.png',addDomain过滤器给它加'https://xxx.com' --> <img :src="imageUrl | addDomain" />
过滤器 addDomain
可以这么写:
filters: { addDomain(path) { return `https://xxx.com${path}` } }
指令的表达式里(比如v-if、v-for)
虽然不常用,但语法上支持,比如用v-if判断时,先过滤数据:
<!-- isShow是数字,filterBoolean把它转成布尔值 --> <div v-if="isShow | filterBoolean">显示内容</div>
过滤器 filterBoolean
返回布尔值:
filters: { filterBoolean(value) { return Boolean(value) // 把数字转成布尔值 } }
只要是模板里能写JS表达式的地方(插值、v-bind、指令的表达式),都能使用filters~
当数据变化时,filters会自动更新不?
这得看过滤器依赖的数据是不是“响应式”:
如果过滤的是Vue的响应式数据(比如data里定义的属性、props传的值),当这些数据变化时,Vue会触发模板重新渲染,过滤器也会跟着重新执行,比如data里的 time
变了,{{ time | formatTime }}
里的formatTime会自动重新计算。
但如果过滤的是非响应式数据(比如自定义的普通变量、函数内部的局部变量),就算数据变了,Vue没检测到变化,过滤器也不会自动更新,举个例子:
export default { data() { return { /* 这里没定义time,time是外面的普通变量 */ } }, mounted() { let time = Date.now() // 非响应式变量 setInterval(() => { time = Date.now() // 改变time,但Vue监听不到 }, 1000) }, filters: { formatTime(value) { return new Date(value).toLocaleTimeString() } } }
模板里用 {{ time | formatTime }}
的话,time变化时页面不会自动更新,因为time不是响应式数据,这时候得手动触发更新(比如用 this.$forceUpdate()
,但不推荐,尽量用响应式数据)。
所以记住:想让filters自动更新,得确保处理的是响应式数据~
Vue3里还能这么用filters不?
Vue3把filters整个移除了~ 官方团队觉得filters的功能,能被更灵活的方式替代(比如methods、computed,或者单独的工具函数),而且Vue3更推崇 Composition API 的逻辑组织方式。
如果项目要从Vue2迁到Vue3,得把filters改成其他写法:
- 全局过滤器:改成工具函数,比如写个
formatTime.js
文件,导出函数,在组件里导入使用。 - 局部过滤器:改成methods里的方法,直接在模板里调用
{{ time | formatTime }}
变成{{ formatTime(time) }}
(formatTime是methods里的函数)。
虽然Vue3不用filters了,但学会Vue2的filters,能帮你理解“格式化逻辑分层”的思路,迁移到Vue3也更容易~
看完这8个问题,再遇到Vue2 filters的知识点,应该就不慌了吧?记住它的定位(展示层格式化)、用法(注册、传参、串联)、和其他选项的区别,再结合实际场景选合适的工具,格式化逻辑就能写得既清晰又高效~ 如果还有疑问,评论区随时喊我~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。