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管理响应式状态 - 将相关状态组合在一起
开发友好:
- 生产环境自动禁用日志
- 清晰的函数命名
灵活性:
- 可以展开或单独暴露表格状态
- 易于在不同组件中复用
这个版本保留了所有原始功能,同时提高了代码的健壮性和可维护性。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
