vue3分页组件与中文化详解
作者:leijmdas
这篇文章主要介绍了vue3分页组件与中文化的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
vue3分页组件与中文化
这段代码实现了一个基于Vue 3和Element Plus的分页组件。
组件支持双向绑定的当前页码(currentPage)和每页条数(pageSize)属性,包含总条数(total)显示和可选每页条数设置,支持页码切换和每页条数变化时触发change事件。
通过el-config-provider配置中文语言环境,组件样式采用flex布局右对齐。
父组件通过v-model绑定分页参数,并在change事件中调用数据获取方法。
import zhCn from "element-plus/es/locale/lang/zh-cn" import {ref} from 'vue' const locale = ref(zhCn) <template> <div class="table-footer"> <el-config-provider :locale="locale"> <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :total="total" :page-sizes="pageSizes" layout="total, sizes, prev, pager, next, jumper" @size-change="handleChange" @current-change="handleChange" /> </el-config-provider> </div> </template> <script> export default { name: 'Pagination', props: { /* 当前页,支持 v-model:page */ currentPage: { type: Number, default: 1 }, /* 每页条数,支持 v-model:limit */ pageSize: { type: Number, default: 10 }, /* 总条数 */ total: { type: Number, default: 0 }, /* 可选每页条数 */ pageSizes: { type: Array, default: () => [10, 20, 30, 40] } }, emits: ['update:currentPage', 'update:pageSize', 'change'], computed: { currentPage: { get() { return this.currentPage }, set(v) { this.$emit('update:currentPage', v) } }, pageSize: { get() { return this.pageSize }, set(v) { this.$emit('update:pageSize', v) } } }, methods: { handleChange() { /* 对外暴露一个 change 事件,参数:{ page, limit } */ this.$emit('change', { currentPage: this.currentPage, pageSize: this.pageSize }) } } } </script> <style scoped> .table-footer { margin-top: 20px; display: flex; justify-content: flex-end; } </style> <script setup> import Pagination from '@/components/Pagination.vue' const currentPage = ref(1) const pageSize = ref(10) const total = ref(0) // 统一获取数据 function getData() { // 这里调用接口 list console.log('拉取第', currentPage.value, '页', pageSize.value, '条') } </script> <template> <div> <Pagination v-model:currentPage="currentPage" v-model:pageSize="pageSize" :total="total" @change="getData" /> </div> </template>
这个代码是一个 Vue 3 的组合式函数 (Composable Function),它封装了一些常用的全局方法和状态管理逻辑。
我来分析并优化这段代码:
代码分析
功能:
- 获取全局属性 ($message, $messageBox, $dict, $api)
- 提供全局状态管理 (Pinia store)
- 封装了常用方法 (确认对话框、日志等)
- 提供了分页和表格相关的响应式状态
优点:
- 使用组合式API封装可复用逻辑
- 集中管理常用工具方法
- 提供了表格和分页的通用状态
可改进点:
- 类型安全(TypeScript)
- 错误处理
- 代码组织
- 响应式状态初始化
优化建议 (TypeScript 版本)
import { reactive, ref, getCurrentInstance, ComponentInternalInstance } from 'vue' import { useGlobalStore } from "../store" import type { MessageBox, Message, DictType, ApiType } from '../types' // 假设有这些类型定义 interface PageParams { currentPage: number pageSize: number total: number } interface TableData<T = any> { list: T[] } interface UserInfo { // 定义用户信息结构 [key: string]: any } export default function useGlobalUtils() { const instance = getCurrentInstance()! const globalProp = instance.appContext.config.globalProperties const globalStore = useGlobalStore() // 类型化全局工具 const getMessage = (): Message => globalProp.$message const getMessageBox = (): MessageBox => globalProp.$messageBox const getDict = (): DictType => globalProp.$dict const getApi = (): ApiType => globalProp.$api // 用户信息(带错误处理) const getUserInfo = (): UserInfo => { try { return JSON.parse(localStorage.userInfo || '{}') } catch (e) { console.error('解析用户信息失败:', e) return {} } } // 确认对话框 const confirm = async (prompt = "确认提交此次编辑吗?"): Promise<boolean> => { try { const isConfirm = await getMessageBox().confirm(prompt, "提示", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) if (isConfirm) { console.log("操作已确认") } return isConfirm } catch (error) { console.error('确认对话框错误:', error) return false } } // 分页状态 const page = reactive<PageParams>({ currentPage: 1, pageSize: 10, total: 0 }) // 表格状态 const tableState = reactive({ data: { list: [] } as TableData, loading: false, itemData: {} as any, dialogLoading: false }) // 日志方法 const log = (...args: any[]) => { if (process.env.NODE_ENV !== 'production') { console.log(...args) } } return { globalStore, getApi, getMessage, getMessageBox, getDict, confirm, log, userInfo: getUserInfo(), page, ...tableState, // 或者分开暴露 // tableData: tableState.data, // tableLoading: tableState.loading, // itemData: tableState.itemData, // dialogLoading: tableState.dialogLoading } }
主要改进点
类型安全:
- 添加了TypeScript类型定义
- 为全局工具方法添加了返回类型
错误处理:
- 添加了JSON解析的错误处理
- 确认对话框添加了try-catch
代码组织:
- 将表格相关状态合并到一个reactive对象中
- 使用更清晰的命名
其他改进:
- 生产环境日志控制
- 更合理的函数命名
- 更好的代码注释
使用建议
在组件中使用:
<script setup lang="ts"> const { page, tableData, confirm, getApi } = useGlobalUtils() // 使用示例 const handleDelete = async () => { if (await confirm('确定删除此项吗?')) { // 执行删除操作 } } </script>
建议将这些工具函数按功能拆分到不同的文件中,例如:
useGlobalTools.ts
(全局工具)useTableState.ts
(表格状态)usePagination.ts
(分页逻辑)
考虑将用户信息也使用Pinia管理,而不是直接从localStorage读取
这样的优化将使代码更健壮、更易维护,并且在使用TypeScript时能获得更好的类型提示和错误检查。
JavaScript 版本的重写
以下是使用纯 JavaScript 重写的代码,保持了原有功能并进行了优化:
import { reactive, ref, getCurrentInstance } from 'vue' import { useGlobalStore } from "../store" export default function useGlobalUtils() { const instance = getCurrentInstance() const globalProp = instance.appContext.config.globalProperties const globalStore = useGlobalStore() // 获取全局工具方法 const getMessage = () => globalProp.$message const getMessageBox = () => globalProp.$messageBox const getDict = () => globalProp.$dict const getApi = () => globalProp.$api // 安全获取用户信息 const getUserInfo = () => { try { return JSON.parse(localStorage.userInfo || '{}') } catch (e) { console.error('解析用户信息失败:', e) return {} } } // 确认对话框封装 const confirm = async (prompt = "确认提交此次编辑吗?") => { try { const isConfirm = await getMessageBox().confirm(prompt, "提示", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) if (isConfirm) { console.log("操作已确认") } return isConfirm } catch (error) { console.error('确认对话框错误:', error) return false } } // 分页状态 const page = reactive({ currentPage: 1, pageSize: 10, total: 0 }) // 表格相关状态 const tableState = reactive({ data: { list: [] }, loading: false, itemData: {}, dialogLoading: false }) // 开发环境日志 const log = (...args) => { if (process.env.NODE_ENV !== 'production') { console.log(...args) } } return { // 全局工具 globalStore, getApi, getMessage, getMessageBox, getDict, // 方法 confirm, log, // 状态 userInfo: getUserInfo(), page, // 表格状态 (可展开或直接暴露) tableData: tableState.data, tableLoading: tableState.loading, itemData: tableState.itemData, dialogLoading: tableState.dialogLoading, // 也可以这样暴露 // ...tableState } }
使用示例
// 在组件中使用 import useGlobalUtils from './useGlobalUtils' export default { setup() { const { page, tableData, confirm, getApi, log } = useGlobalUtils() // 获取数据示例 const fetchData = async () => { try { tableData.loading = true const response = await getApi().get('/data', { params: { page: page.currentPage, size: page.pageSize } }) tableData.list = response.data.list page.total = response.data.total } catch (error) { log('获取数据失败:', error) getMessage().error('获取数据失败') } finally { tableData.loading = false } } // 删除确认示例 const handleDelete = async (id) => { if (await confirm('确定删除此项吗?')) { try { await getApi().delete(`/data/${id}`) getMessage().success('删除成功') fetchData() // 刷新数据 } catch (error) { log('删除失败:', error) getMessage().error('删除失败') } } } return { page, tableData, handleDelete, fetchData } } }
主要特点
- 纯 JavaScript 实现:完全使用 ES6+ 语法
- 错误处理增强:添加了关键操作的错误捕获
状态管理优化:
- 使用
reactive
和ref
管理响应式状态 - 将相关状态组合在一起
开发友好:
- 生产环境自动禁用日志
- 清晰的函数命名
灵活性:
- 可以展开或单独暴露表格状态
- 易于在不同组件中复用
这个版本保留了所有原始功能,同时提高了代码的健壮性和可维护性。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。