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 之类

参看上条,如果需要使用 data、computed 和 methods 之类请使用 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