在开发中,你是否经常遇到这样的需求?
"后端返回的时间是
2025-09-19 10:30:00
,但我想在页面上显示为'3天前'。"
"价格是99.9
,但需要显示为¥99.90
。"
传统做法是:
js
// ❌ 在 computed 或 methods 中处理
computed: {
formattedPrice() {
return '¥' + this.price.toFixed(2);
}
}
但这样会让组件逻辑变得臃肿。
Vue 过滤器(Filters) 正是为这类场景而生的解决方案。
一、什么是过滤器?
✅ 定义
过滤器(Filter) 是一个纯函数 ,用于格式化 数据的展示,不改变原始数据,只改变用户看到的输出。
📌 核心特点
特性 | 说明 |
---|---|
不修改数据 | 原始数据保持不变 |
专注展示层 | 只影响模板中的显示 |
可链式调用 | 多个过滤器串联使用 |
声明式语法 | 使用操作符 |
二、过滤器 vs computed vs methods
对比项 | filters |
computed |
methods |
---|---|---|---|
是否修改数据 | ❌ 否 | ✅ 可能 | ✅ 可能 |
是否缓存 | ❌ 否 | ✅ 是 | ❌ 否 |
使用场景 | 格式化显示 | 数据计算 | 事件处理 |
调用方式 | `{{ value | filter }}` | {{ computedValue }} |
📌 示例对比
js
data() {
return {
price: 99.9,
date: '2025-09-16 10:30:00'
};
}
方案 1:使用 filters
(推荐)
html
<p>价格:{{ price | currency }}</p>
<p>时间:{{ date | timeAgo }}</p>
js
filters: {
currency(price) {
return price ? `¥${price.toFixed(2)}` : '--';
},
timeAgo(dateStr) {
const date = new Date(dateStr);
const diff = (Date.now() - date) / 1000;
if (diff < 60) return '刚刚';
if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`;
if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`;
return `${Math.floor(diff / 86400)}天前`;
}
}
方案 2:使用 computed
js
computed: {
displayPrice() {
return this.price ? `¥${this.price.toFixed(2)}` : '--';
},
displayTime() {
// 同上 timeAgo 逻辑
}
}
html
<p>价格:{{ displayPrice }}</p>
<p>时间:{{ displayTime }}</p>
❌ 问题:每个需要格式化的字段都要定义一个
computed
,代码重复。
三、如何实现一个过滤器?
✅ 1. 局部过滤器(组件内)
js
export default {
data() {
return {
price: 99.9,
text: 'hello world'
};
},
filters: {
// 价格格式化
currency(value) {
return value != null ? `¥${value.toFixed(2)}` : '--';
},
// 首字母大写
capitalize(value) {
if (!value) return '';
return value.toString().charAt(0).toUpperCase() + value.slice(1);
},
// 截取字符串
truncate(value, length = 10) {
if (!value) return '';
return value.length > length ? value.slice(0, length) + '...' : value;
}
}
}
html
<template>
<div>
<p>价格:{{ price | currency }}</p>
<p>标题:{{ text | capitalize }}</p>
<p>摘要:{{ text | truncate(5) }}</p>
</div>
</template>
✅ 2. 全局过滤器(推荐复用)
js
// filters.js
export const currency = (value) => {
return value != null ? `¥${value.toFixed(2)}` : '--';
};
export const timeAgo = (dateStr) => {
// 同上逻辑
};
// main.js
import Vue from 'vue';
import * as filters from './filters';
// 注册所有过滤器
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key]);
});
html
<!-- 任何组件中均可使用 -->
<p>{{ price | currency }}</p>
<p>{{ date | timeAgo }}</p>
四、过滤器的高级用法
✅ 1. 链式调用
html
<p>{{ text | capitalize | truncate(10) }}</p>
<!-- 先大写,再截取 -->
✅ 2. 接收多个参数
js
filters: {
slice(value, start, end) {
return value.slice(start, end);
}
}
html
<p>{{ 'Hello World' | slice(0, 5) }}</p>
<!-- 输出:Hello -->
✅ 3. 在 v-bind
中使用(Vue 2.1.0+)
html
<div v-bind:id="rawId | formatId"></div>
js
filters: {
formatId(id) {
return 'user-' + id;
}
}
五、Vue 3 中的过滤器
⚠️ 重要更新 :Vue 3 已移除过滤器语法。
❌ Vue 3 不再支持
html
<!-- Vue 3 中无效 -->
<p>{{ price | currency }}</p>
✅ 替代方案
方案 1:使用 methods
js
methods: {
currency(price) {
return price ? `¥${price.toFixed(2)}` : '--';
}
}
html
<p>{{ currency(price) }}</p>
方案 2:使用 computed
(适合复杂逻辑)
方案 3:使用组合式函数(推荐)
js
// composables/useFilters.js
export function useFilters() {
const currency = (value) => {
return value != null ? `¥${value.toFixed(2)}` : '--';
};
const timeAgo = (dateStr) => {
// ...
};
return { currency, timeAgo };
}
js
// 组件中
import { useFilters } from '@/composables/useFilters';
export default {
setup() {
const { currency, timeAgo } = useFilters();
return { currency, timeAgo };
}
}
html
<p>{{ currency(price) }}</p>
六、最佳实践
✅ 推荐使用场景
场景 | 示例 |
---|---|
货币格式化 | ¥99.90 , $100.00 |
日期格式化 | 2025-09-19 , 3天前 |
文本处理 | 大写、截取、转义 |
单位添加 | km , kg , ℃ |
❌ 不推荐使用场景
场景 | 原因 |
---|---|
复杂计算 | 应使用 computed |
异步操作 | 过滤器必须是同步的 |
数据转换(影响逻辑) | 应在 computed 或 methods 中处理 |
💡 结语
"过滤器是展示层的'化妆师',只负责美,不负责变。"
- ✅ 优点:语法简洁、逻辑分离、易于复用;
- ⚠️ 缺点:Vue 3 已移除,需迁移;
- 💡 建议:在 Vue 2 项目中合理使用;Vue 3 项目使用组合式函数替代。
掌握过滤器,让你的代码更清晰,展示更优雅。