vue-pure-admin过滤器开发:自定义过滤器与全局过滤器注册
前言:为什么需要过滤器?
在日常的前端开发中,我们经常需要对数据进行格式化处理,比如日期格式化、金额格式化、文本截断等。Vue.js 提供了过滤器(Filter)机制,可以让我们在模板中对数据进行简单的格式化处理,而无需在组件中编写复杂的计算属性或方法。
在 vue-pure-admin 这样的企业级后台管理系统中,过滤器更是不可或缺的工具,它能够:
- 提高代码复用性:相同的格式化逻辑可以在多个组件中共享
- 保持模板简洁:避免在模板中嵌入复杂的JavaScript表达式
- 统一格式化标准:确保整个项目的格式化风格一致
过滤器基础概念
什么是Vue过滤器?
Vue过滤器是一种可以在模板中使用的特殊函数,用于对数据进行格式化处理。过滤器通过管道符 | 调用,可以链式使用多个过滤器。
<!-- 基础用法 -->
<p>{{ message | capitalize }}</p>
<!-- 链式调用 -->
<p>{{ price | currency | toFixed(2) }}</p>
<!-- 带参数的过滤器 -->
<p>{{ date | formatDate('YYYY-MM-DD') }}</p>
Vue 2 vs Vue 3 过滤器差异
在Vue 3中,过滤器的使用方式有所变化:
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 全局注册 | Vue.filter() | app.config.globalProperties.$filters |
| 局部注册 | filters 选项 | 组合式API函数 |
| 推荐方式 | 过滤器 | 计算属性/方法 |
虽然Vue 3官方推荐使用计算属性或方法代替过滤器,但在某些场景下,过滤器仍然有其独特的优势。
在vue-pure-admin中实现过滤器
1. 创建过滤器工具文件
首先,我们在 src/utils 目录下创建过滤器工具文件:
// src/utils/filters.ts
/**
* 金额格式化过滤器
* @param value 金额数值
* @param symbol 货币符号,默认为¥
* @param decimals 小数位数,默认为2
* @returns 格式化后的金额字符串
*/
export const currencyFilter = (value: number | string, symbol: string = '¥', decimals: number = 2): string => {
if (value == null || value === '') return ''
const num = typeof value === 'string' ? parseFloat(value) : value
if (isNaN(num)) return ''
return symbol + num.toFixed(decimals).replace(/\d(?=(\d{3})+\.)/g, '$&,')
}
/**
* 日期格式化过滤器
* @param value 日期值
* @param format 格式字符串,默认为'YYYY-MM-DD'
* @returns 格式化后的日期字符串
*/
export const dateFilter = (value: string | Date, format: string = 'YYYY-MM-DD'): string => {
if (!value) return ''
const date = typeof value === 'string' ? new Date(value) : value
if (isNaN(date.getTime())) return ''
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return format
.replace('YYYY', String(year))
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('mm', minutes)
.replace('ss', seconds)
}
/**
* 文本截断过滤器
* @param text 原始文本
* @param length 最大长度,默认为20
* @param suffix 后缀,默认为'...'
* @returns 截断后的文本
*/
export const truncateFilter = (text: string, length: number = 20, suffix: string = '...'): string => {
if (!text || typeof text !== 'string') return ''
return text.length > length ? text.substring(0, length) + suffix : text
}
/**
* 数字千分位格式化
* @param value 数字值
* @returns 格式化后的数字字符串
*/
export const numberFilter = (value: number | string): string => {
if (value == null || value === '') return ''
const num = typeof value === 'string' ? parseFloat(value) : value
if (isNaN(num)) return ''
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
/**
* 状态文本映射过滤器
* @param value 状态值
* @param mapping 状态映射对象
* @returns 对应的状态文本
*/
export const statusFilter = (value: any, mapping: Record<string, string>): string => {
return mapping[value] || value
}
/**
* 文件大小格式化
* @param bytes 字节数
* @param decimals 小数位数
* @returns 格式化后的文件大小
*/
export const fileSizeFilter = (bytes: number, decimals: number = 2): string => {
if (bytes === 0) return '0 Bytes'
const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i]
}
2. 全局过滤器注册
在 src/main.ts 中注册全局过滤器:
// src/main.ts (在现有代码基础上添加)
import * as filters from '@/utils/filters'
// 在创建app实例后,注册全局过滤器
const app = createApp(App)
// 注册全局过滤器
app.config.globalProperties.$filters = filters
// 同时提供类型声明
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$filters: typeof filters
}
}
3. 创建类型声明文件
为了更好的TypeScript支持,创建类型声明文件:
// src/types/filters.d.ts
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$filters: {
currencyFilter: (value: number | string, symbol?: string, decimals?: number) => string
dateFilter: (value: string | Date, format?: string) => string
truncateFilter: (text: string, length?: number, suffix?: string) => string
numberFilter: (value: number | string) => string
statusFilter: (value: any, mapping: Record<string, string>) => string
fileSizeFilter: (bytes: number, decimals?: number) => string
}
}
}
export {}
过滤器的使用方式
在模板中使用全局过滤器
<template>
<div class="demo-container">
<!-- 金额格式化 -->
<p>价格:{{ 1999.99 | $filters.currencyFilter('¥', 2) }}</p>
<!-- 日期格式化 -->
<p>创建时间:{{ new Date() | $filters.dateFilter('YYYY-MM-DD HH:mm:ss') }}</p>
<!-- 文本截断 -->
<p>描述:{{ longText | $filters.truncateFilter(50, '...') }}</p>
<!-- 数字千分位 -->
<p>用户数:{{ 1234567 | $filters.numberFilter }}</p>
<!-- 状态映射 -->
<p>状态:{{ status | $filters.statusFilter(statusMapping) }}</p>
<!-- 文件大小 -->
<p>文件大小:{{ 1048576 | $filters.fileSizeFilter }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const longText = ref('这是一段非常长的文本内容,需要进行截断处理以避免影响页面布局')
const status = ref(1)
const statusMapping = {
0: '禁用',
1: '启用',
2: '待审核'
}
</script>
在组合式API中使用过滤器
<template>
<div>
<p>{{ formattedPrice }}</p>
<p>{{ formattedDate }}</p>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useFilters } from '@/composables/useFilters'
const { currencyFilter, dateFilter } = useFilters()
const price = 1999.99
const date = new Date()
const formattedPrice = computed(() => currencyFilter(price, '¥', 2))
const formattedDate = computed(() => dateFilter(date, 'YYYY-MM-DD HH:mm'))
</script>
创建组合式API钩子
为了更好地在组合式API中使用过滤器,我们可以创建一个专门的钩子:
// src/composables/useFilters.ts
import { currencyFilter, dateFilter, truncateFilter, numberFilter, statusFilter, fileSizeFilter } from '@/utils/filters'
export function useFilters() {
return {
currencyFilter,
dateFilter,
truncateFilter,
numberFilter,
statusFilter,
fileSizeFilter
}
}
高级过滤器开发技巧
1. 过滤器组合与链式调用
<template>
<div>
<!-- 链式调用多个过滤器 -->
<p>{{ price | $filters.currencyFilter | $filters.truncateFilter(10) }}</p>
</div>
</template>
2. 带参数的动态过滤器
// 动态货币符号过滤器
export const dynamicCurrencyFilter = (value: number, currencyCode: string = 'CNY') => {
const symbols: Record<string, string> = {
CNY: '¥',
USD: '$',
EUR: '€',
JPY: '¥'
}
const symbol = symbols[currencyCode] || currencyCode
return currencyFilter(value, symbol)
}
3. 异步数据过滤器
// 异步数据格式化过滤器
export const asyncDataFilter = async (value: any, formatter: (data: any) => Promise<string>) => {
try {
return await formatter(value)
} catch (error) {
console.error('Async filter error:', error)
return '格式化失败'
}
}
过滤器的最佳实践
1. 性能优化建议
// 使用记忆化技术优化频繁调用的过滤器
import { memoize } from 'lodash-es'
export const memoizedCurrencyFilter = memoize(currencyFilter, (value, symbol, decimals) =>
`${value}-${symbol}-${decimals}`
)
2. 错误处理机制
// 增强的错误处理过滤器
export const safeFilter = <T>(filterFn: (...args: any[]) => T, defaultValue: T = '' as any) => {
return (...args: any[]): T => {
try {
return filterFn(...args)
} catch (error) {
console.warn('Filter execution failed:', error)
return defaultValue
}
}
}
// 使用安全包装
export const safeCurrencyFilter = safeFilter(currencyFilter, '¥0.00')
3. 国际化支持
// 支持国际化的过滤器
import { useI18n } from 'vue-i18n'
export const createI18nFilters = () => {
const { t } = useI18n()
return {
i18nStatusFilter: (value: any, mappingKey: string) => {
const mapping = t(mappingKey) as Record<string, string>
return statusFilter(value, mapping)
}
}
}
实际应用场景示例
场景1:表格数据格式化
<template>
<el-table :data="tableData">
<el-table-column prop="price" label="价格">
<template #default="{ row }">
{{ row.price | $filters.currencyFilter }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="{ row }">
{{ row.createTime | $filters.dateFilter('YYYY-MM-DD') }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status | $filters.statusFilter(statusMapping) }}
</el-tag>
</template>
</el-table-column>
</el-table>
</template>
场景2:表单展示优化
<template>
<el-descriptions :column="2" border>
<el-descriptions-item label="订单金额">
{{ order.amount | $filters.currencyFilter }}
</el-descriptions-item>
<el-descriptions-item label="下单时间">
{{ order.createTime | $filters.dateFilter('YYYY-MM-DD HH:mm') }}
</el-descriptions-item>
<el-descriptions-item label="商品描述">
{{ order.description | $filters.truncateFilter(30) }}
</el-descriptions-item>
</el-descriptions>
</template>
测试与调试
单元测试示例
// tests/unit/filters.spec.ts
import { currencyFilter, dateFilter } from '@/utils/filters'
describe('Filters', () => {
describe('currencyFilter', () => {
it('should format number correctly', () => {
expect(currencyFilter(1234.56)).toBe('¥1,234.56')
expect(currencyFilter('1234.56', '$')).toBe('$1,234.56')
})
it('should handle invalid input', () => {
expect(currencyFilter(null)).toBe('')
expect(currencyFilter('abc')).toBe('')
})
})
describe('dateFilter', () => {
it('should format date correctly', () => {
const date = new Date('2023-01-01T12:00:00')
expect(dateFilter(date, 'YYYY-MM-DD')).toBe('2023-01-01')
expect(dateFilter(date, 'YYYY-MM-DD HH:mm')).toBe('2023-01-01 12:00')
})
})
})
调试技巧
// 添加调试信息的过滤器
export const debugFilter = (value: any, label: string = '') => {
console.log(`[Filter Debug] ${label}:`, value)
return value
}
// 使用方式
{{ someValue | debugFilter('someValue') | $filters.currencyFilter }}
总结
在 vue-pure-admin 项目中实现过滤器开发,我们需要注意以下几点:
- 遵循Vue 3最佳实践:虽然Vue 3推荐使用计算属性,但过滤器在特定场景下仍有其价值
- 类型安全:为所有过滤器提供完整的TypeScript类型定义
- 性能考虑:对频繁调用的过滤器使用记忆化技术
- 错误处理:确保过滤器在异常情况下能够优雅降级
- 国际化支持:考虑多语言环境下的过滤器需求
通过合理的过滤器设计,可以显著提高代码的可维护性和开发效率,特别是在数据展示密集的后台管理系统中。过滤器不仅能让模板代码更加简洁,还能确保整个项目的格式化风格统一。
记住,过滤器的核心价值在于代码复用和关注点分离,合理使用过滤器可以让你的vue-pure-admin项目更加专业和易维护。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



