Code前端首页关于Code前端联系我们

Vue2里的filters到底怎么用?一篇文章讲透常见问题

terry 8小时前 阅读数 11 #Vue
文章标签 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 接收的是 timeformat 接收的是 '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前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门