vue-pure-admin过滤器开发:自定义过滤器与全局过滤器注册

vue-pure-admin过滤器开发:自定义过滤器与全局过滤器注册

【免费下载链接】vue-pure-admin 全面ESM+Vue3+Vite+Element-Plus+TypeScript编写的一款后台管理系统(兼容移动端) 【免费下载链接】vue-pure-admin 项目地址: https://gitcode.com/GitHub_Trending/vu/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 2Vue 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 项目中实现过滤器开发,我们需要注意以下几点:

  1. 遵循Vue 3最佳实践:虽然Vue 3推荐使用计算属性,但过滤器在特定场景下仍有其价值
  2. 类型安全:为所有过滤器提供完整的TypeScript类型定义
  3. 性能考虑:对频繁调用的过滤器使用记忆化技术
  4. 错误处理:确保过滤器在异常情况下能够优雅降级
  5. 国际化支持:考虑多语言环境下的过滤器需求

通过合理的过滤器设计,可以显著提高代码的可维护性和开发效率,特别是在数据展示密集的后台管理系统中。过滤器不仅能让模板代码更加简洁,还能确保整个项目的格式化风格统一。

记住,过滤器的核心价值在于代码复用关注点分离,合理使用过滤器可以让你的vue-pure-admin项目更加专业和易维护。

【免费下载链接】vue-pure-admin 全面ESM+Vue3+Vite+Element-Plus+TypeScript编写的一款后台管理系统(兼容移动端) 【免费下载链接】vue-pure-admin 项目地址: https://gitcode.com/GitHub_Trending/vu/vue-pure-admin

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值