简介:本文详解如何基于Vue3、Vite、TypeScript、Pinia和Router4二次封装ElementPlus表格组件,打造高复用、强类型的后台管理系统表格方案。
在Vue3+TypeScript的技术栈下,ElementPlus的表格组件虽然功能强大,但在实际后台管理系统开发中仍存在诸多痛点:重复代码多、类型定义繁琐、功能扩展困难、与状态管理耦合度高等。本文将从零开始,基于Vue3组合式API、Vite构建工具、TypeScript严格类型检查、Pinia状态管理和Router4路由,构建一个”完美”的表格二次封装方案。
npm create vite@latest my-admin -- --template vue-tscd my-adminnpm install element-plus @element-plus/icons-vue pinia vue-router@4
// types/table.d.tsexport interface TableColumn {prop: string;label: string;width?: number | string;fixed?: 'left' | 'right';sortable?: boolean | string;formatter?: (row: any, column: any, cellValue: any) => string;// 更多类型定义...}export interface TableProps {columns: TableColumn[];data: any[];loading?: boolean;pagination?: {currentPage: number;pageSize: number;total: number;};// 更多props定义...}
// composables/useTable.tsimport { ref, computed } from 'vue'import type { TableColumn, TableProps } from '@/types/table'export function useTable(initialProps: Partial<TableProps>) {const props = ref<TableProps>({columns: [],data: [],...initialProps})const selectedRows = ref<any[]>([])const handleSelectionChange = (rows: any[]) => {selectedRows.value = rows}return {props,selectedRows,handleSelectionChange// 更多方法...}}
<!-- components/BaseTable.vue --><template><el-table:data="props.data"v-loading="props.loading"@selection-change="handleSelectionChange"><el-table-columnv-for="column in props.columns":key="column.prop":prop="column.prop":label="column.label":width="column.width":fixed="column.fixed":sortable="column.sortable"><template #default="{ row }"><slot :name="`column-${column.prop}`" :row="row">{{ column.formatter ? column.formatter(row, column, row[column.prop]) : row[column.prop] }}</slot></template></el-table-column></el-table></template><script setup lang="ts">import { useTable } from '@/composables/useTable'const props = defineProps<TableProps>()const emit = defineEmits(['selection-change'])const { handleSelectionChange } = useTable(props)</script>
// composables/useTablePagination.tsimport { ref, watch } from 'vue'export function useTablePagination(fetchData: (params: any) => Promise<void>) {const pagination = ref({currentPage: 1,pageSize: 10,total: 0})const handleSizeChange = (size: number) => {pagination.value.pageSize = sizefetchData(getParams())}const handleCurrentChange = (page: number) => {pagination.value.currentPage = pagefetchData(getParams())}const getParams = () => ({page: pagination.value.currentPage,size: pagination.value.pageSize})return {pagination,handleSizeChange,handleCurrentChange}}
// stores/tableStore.tsimport { defineStore } from 'pinia'export const useTableStore = defineStore('table', {state: () => ({tableData: [],loading: false,searchParams: {}}),actions: {async fetchTableData(params: any) {this.loading = truetry {// 调用API获取数据const res = await api.getTableData(params)this.tableData = res.data.list// 更新分页总数// ...} finally {this.loading = false}}}})
<!-- views/UserManagement.vue --><template><div class="user-management"><BaseTable:columns="columns":data="tableStore.tableData":loading="tableStore.loading":pagination="pagination"@size-change="handleSizeChange"@current-change="handleCurrentChange"><template #column-action="{ row }"><el-button @click="handleEdit(row)">编辑</el-button><el-button type="danger" @click="handleDelete(row)">删除</el-button></template></BaseTable></div></template><script setup lang="ts">import { onMounted } from 'vue'import { useTableStore } from '@/stores/tableStore'import { useTablePagination } from '@/composables/useTablePagination'const tableStore = useTableStore()const { pagination, handleSizeChange, handleCurrentChange } = useTablePagination(tableStore.fetchTableData)const columns = [{ prop: 'name', label: '姓名', width: 120 },{ prop: 'age', label: '年龄', sortable: true },{ prop: 'address', label: '地址' },{ prop: 'action', label: '操作', fixed: 'right' }]onMounted(() => {tableStore.fetchTableData({ page: 1, size: 10 })})</script>
// router/index.tsimport { createRouter, createWebHistory } from 'vue-router'import UserManagement from '@/views/UserManagement.vue'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/user',name: 'user',component: UserManagement,meta: { requiresAuth: true }}]})
一个”完美”的ElementPlus表格二次封装,不是功能的简单堆砌,而是通过合理的架构设计,在类型安全、功能完整性和开发体验之间找到最佳平衡点。基于Vue3+Vite+TypeScript+Pinia+Router4的技术栈,我们不仅能够构建出强大的表格组件,更能为整个后台管理系统奠定良好的技术基础。这种封装方式在实际项目中已经验证了其稳定性和可维护性,值得在中大型项目中推广使用。