在 Vue 2 中,过滤器(filters) 是一种非常实用的语法糖,用于在模板中对数据进行格式化输出处理。我们来深入理解过滤器的原理、使用方式、最佳实践以及其局限性。
vue2
🧠 本质是什么?
Vue 2 的过滤器是一个 纯函数,用于在模板表达式的 插值语法中 对值进行处理。
它不会修改原始数据,只影响显示结果。
🧪 语法结构
{{ value | filterName }}
多个过滤器可以链式调用:
{{ value | filterA | filterB }}
✅ 使用方式
全局过滤器
// main.js
Vue.filter('capitalize', function (value) {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
})
使用:
{{ 'hello' | capitalize }} <!-- 输出:Hello -->
局部过滤器
export default {
data() {
return { msg: 'vue' }
},
filters: {
upper(value) {
return value.toUpperCase()
}
}
}
模板中使用:
{{ msg | upper }} <!-- 输出:VUE -->
🔍 过滤器的工作原理
Vue 会在编译模板时识别 v-text 或插值中的 | 符号,转为调用该过滤器函数,并将其作用在表达式的输出上。
等价于这样:
<!-- 模板 -->
{{ price | currency }}
<!-- 编译后 -->
{{ _f("currency")(price) }}
_f 是 Vue 内部用于查找过滤器的方法。
⸻
🧰 实战场景示例
日期格式化
Vue.filter('formatDate', val => {
const date = new Date(val)
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
})
{{ createdAt | formatDate }}
金额保留两位小数
Vue.filter('currency', val => {
return '¥' + Number(val).toFixed(2)
})
首字母大写
Vue.filter('capitalize', val => {
if (!val) return ''
return val.charAt(0).toUpperCase() + val.slice(1)
})
⚠️ 过滤器的局限性
限制项 | 描述 |
---|---|
📦 仅限插值表达式中使用 | 不能在 v-if、v-bind、v-model 中使用 |
🔗 无法接收多个参数(只能通过函数封装间接实现) | |
🧼 Vue 3 中已废弃 | 因为它破坏了模板的“逻辑少”原则,推荐用方法或计算属性 |
vue3中的替换方案
在 Vue 3 中,过滤器(filters)被彻底移除,原因是它们违反了“模板中逻辑最少化”的设计理念。Vue 团队推荐用以下三种方式来 优雅替代过滤器功能:
⸻
✅ 计算属性(computed) —— 推荐用于“无参数、依赖响应式数据”的格式化
<template>
<p>价格:{{ formattedPrice }}</p>
</template>
<script setup>
import { ref, computed } from 'vue'
const price = ref(88)
const formattedPrice = computed(() => {
return '¥' + price.value.toFixed(2)
})
</script>
⸻
✅ 方法(methods) —— 推荐用于“需要传参”的格式处理
<template>
<p>创建日期:{{ formatDate(createdAt) }}</p>
</template>
<script setup>
const createdAt = '2025-05-23T10:30:00'
function formatDate(dateStr) {
const d = new Date(dateStr)
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`
}
</script>
✅ 全局方法或 composable —— 推荐用于多个组件共用的格式逻辑
方式一:封装为工具函数
// utils/formatters.js
export function capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
<script setup>
import { capitalize } from '@/utils/formatters'
const name = 'vue'
</script>
<template>
<p>{{ capitalize(name) }}</p>
</template>
方式二:封装为 composable
// composables/useFormatters.js
export function useFormatters() {
const currency = (val) => '¥' + Number(val).toFixed(2)
const capitalize = (val) => val.charAt(0).toUpperCase() + val.slice(1)
return { currency, capitalize }
}
<script setup>
import { useFormatters } from '@/composables/useFormatters'
const { currency, capitalize } = useFormatters()
</script>
<template>
<p>{{ currency(199.9) }}</p>
<p>{{ capitalize('hello') }}</p>
</template>
🔍 对比总结
替代方式 | 使用场景 | 是否推荐 |
---|---|---|
computed | 无参、基于响应式变量的格式化 | ✅ 推荐 |
methods | 需要传参或临时格式化逻辑 | ✅ 推荐 |
工具函数/composables | 多组件复用的格式工具 | ✅ 强烈推荐 |
自定义指令 | 不推荐替代过滤器(逻辑不同) | ❌ 不推荐 |
例子
当然可以!我们来做一个完整的例子:
🧩 Vue 2 中的过滤器写法(要转换的代码)
<template>
<div>
<p>用户名:{{ username | capitalize }}</p>
<p>价格:{{ price | currency }}</p>
</div>
</template>
<script>
export default {
data() {
return {
username: 'vue',
price: 199.99
}
},
filters: {
capitalize(value) {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
},
currency(value) {
return '¥' + Number(value).toFixed(2)
}
}
}
</script>
✅ Vue 3 中的替代方案(使用 setup + methods)
<template>
<div>
<p>用户名:{{ capitalize(username) }}</p>
<p>价格:{{ currency(price) }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('vue')
const price = ref(199.99)
function capitalize(value) {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
}
function currency(value) {
return '¥' + Number(value).toFixed(2)
}
</script>
改成通用模块
当然!下面是一个完整的 Vue 3 示例,演示如何将原来 Vue 2 的过滤器功能 抽离为通用模块(utils/formatters.js) 并在组件中使用。
📁 目录结构建议
src/
├── components/
│ └── UserInfo.vue
├── utils/
│ └── formatters.js
✅ 创建通用模块:utils/formatters.js
// src/utils/formatters.js
export function capitalize(value) {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
}
export function currency(value) {
const num = Number(value)
return isNaN(num) ? '¥0.00' : '¥' + num.toFixed(2)
}
export function formatDate(value) {
if (!value) return ''
const d = new Date(value)
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`
}
⸻
✅ 使用模块的组件示例:components/UserInfo.vue
<template>
<div class="p-4 border rounded">
<p>用户名:{{ capitalize(username) }}</p>
<p>价格:{{ currency(price) }}</p>
<p>注册时间:{{ formatDate(joinDate) }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { capitalize, currency, formatDate } from '@/utils/formatters'
const username = ref('vue')
const price = ref(199.99)
const joinDate = ref('2025-05-01T10:20:00')
</script>
⸻
🎯 使用说明
- 你可以将 utils/formatters.js 视为一个工具库,只负责数据格式化逻辑。
- 在任何 Vue 组件中使用 import { … } from ‘@/utils/formatters’ 来引入。
- 保持模板逻辑简洁,所有格式化都由函数控制,易维护、易测试。