VueJS 的过滤器 filter API

一直没有怎么用过 Vue 的 过滤器 API,都是直接用 AntD Pro 当中提供的数字千分格式化、时间格式化之类的,没有自己去声明过,主要是因为 Array.prototype.filter 的先入为主,一直把 vue.filter 理解成为了筛选,而不是过滤器。

其实,vue.filter 是借鉴了 Linux 当中的 Pipe 符号 (|) 来处理数据 ,然后借用了 filter 这个名字:

利用 Linux 所提供的管道符 “|” 将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入

其实我觉得如果直接用 pipe 来命名其实就更好理解了,但是也许是因为前端圈子接触到 pipe 的人并不多,使用 filter 这个熟悉的单词可能更加容易让大众接受。

使用起来确实很方便,用 | 符号分隔就行,会按照 从前往后的顺序 依次 传入过滤器,然后返回转换后的值。

等到后来再遇到适合的场景想起来使用 filter ,但又因为项目的历史原因没有去使用,因为自己都是局部使用 computed计算方法调用返回 来处理(也是Vue3所推荐的替代过滤器的方式

初步使用:在组件中使用过滤器

过滤器可以用在两个地方(可以直接的使用方式有 2 种)

  1. 在双花括号中 {{ message | filterName }};
  2. v-bind<div v-bind:id="message | filterName"></div>

那如果说我要使用多个过滤器呢?
例如:{{ message | filterA | filterB }} 会先传入 filterA 去处理,filterA 返回的结果继续传入给 filterB 最后展示的值就是 filterB 返回的结果。

🌰 DEMO:

<template>
  <div id="app">
    <span>{{ price | NumberFormat | FilterDollarSign }}</span> 
    <!-- 渲染结果是 $ 199,999,999 -->
  </div>
</template>
<script>
export default {
  data() {
    return {
      price:199999999,
    };
  },
  filters:{
    NumberFormat(value) {
      if (!value) return '0'
      const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
      return intPartFormat
    },
    FilterDollarSign(price){
      return `$ ${price}`
    }
  },
};
</script>

✨ 多参数 过滤器 的情况

例如,需要传入 两个参数 的过滤器,刨开第一个默认传入的参数,键入第二个参数即可: {{ price | NumberFormat(2) }} , 三个参数: {{ price | NumberFormat(2, '$') }},更多参数以此类推。

<template>
  <div id="app">
    <span>{{ price | NumberFormat(2, '$') }}</span> 
    <!-- 渲染结果是 $ 0.67 -->
  </div>
</template>
<script>
export default {
  data() {
    return {
      price:0.6666,
    };
  },
  filters:{
    NumberFormat(value, limit, sign) {
      if (!value) return '0'
      const intPartFormat = value.toFixed(limit).toString()
      return `${sign}  ${intPartFormat}`
    }
  },
};
</script>

更进一步:使用全局过滤器

在项目的不断完善中,会有出现一些重复使用的过滤器,如果每次都重新声明就很麻烦,就可以注册 全局过滤器 vue.filter

🌰 栗子:

// main.js
Vue.filter('NumberFormat', function (value) {
  if (!value) {
    return '0'
  }
  const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
  return intPartFormat
})
new Vue({
  // options
}).$mount('#app')

然后就可以在全局直接使用这个过滤器了,不需要单独再声明或者引入

当然如果全部都直接在 main.js 当中书写很多过滤器就很容易让 main.js 内容过多,所以可以提取出来,例如 ant-design-vue-pro/filter.js,然后再 import 进来就可以了 ant-design-vue-pro/main.js

✨ 全局和局步同名冲突

当全局过滤器和局部过滤器重名时,会采用局部过滤器。

✨ 以上说的都是在 <template> 当中使用过滤器,如果我想在 methods 当中使用呢?

全局过滤器的话,可以直接使用文档中的 var myFilter = Vue.filter('my-filter') 来获取,然后就可以把 myFilter 当成一个函数使用了,
如果时当前组件的过滤器的,可以使用 this.$options.filters['my-filter'] 来获取,调用方式和上边一样。

🎐 尾声

适合过滤器的场景

一般是简单的字符串处理,例如上边提到的添加数字千分号、把 状态key 转换成 状态label 之类的。

过滤器中如何使用当前组件的 data 或者 methods 之类

参看上条,如果需要使用 datacomputedmethods 之类请使用 computed 替代 filter

VueJS 3.x 当中的 filter 已删除

In 3.x, filters are removed and no longer supported. Instead, we recommend replacing them with method calls or computed properties.
3.x 中,过滤器已删除,不再支持。相反地,我们建议用方法调用计算属性替换它们。

🔗 资源

Filters | Vue.js - v2.x
Filters | Vue.js - v3.x