基于 element-plus 的表格组件二次封装:思路与使用指南
引言
在前端开发中,表格是展示数据的常用组件。Element Plus 提供了强大的表格组件,但在实际项目中,为了提高开发效率和代码的复用性,我们常常需要对其进行二次封装。本文将详细介绍基于 Element Plus 二次封装表格组件的思路,并给出使用说明。源码地址:https://gitcode.com/Jiaberrr/vue3-pc-template/overview,演示地址:https://env-00jxt0stsnl3-static.normal.cloudstatic.cn/index.html
封装思路
组件结构设计
我们的目标是封装一个通用的表格组件,它既包含表格展示部分,又包含分页功能。整体组件结构如下:
- 表格部分:使用
el-table
作为基础组件,通过传入不同的属性和插槽来定制表格的外观和内容。 - 分页部分:使用
el-pagination
组件,实现分页功能,通过与表格数据的交互,实现数据的分页展示。
属性设计
为了使组件具有通用性,我们设计了一系列属性:
border
:控制表格是否有边框,类型为Boolean
,默认值为true
。align
:设置表格内容的对齐方式,类型为String
,默认值为center
。tableConfig
:这是一个数组,用于配置表格的列信息,是必填项。每个元素包含label
(列名)、width
(列宽)、prop
(对应数据的属性名)等信息,还可以包含slot
(是否使用插槽)、slotName
(插槽名)、formatter
(数据格式化函数)等自定义属性。tableData
:表格展示的数据,类型为Array
,默认值为空数组。selection
:控制表格是否显示复选框,用于多选功能,类型为Boolean
,默认值为false
。showIndex
:控制表格是否显示序号列,类型为Boolean
,默认值为true
。pagination
:控制是否显示分页组件,类型为Boolean
,默认值为true
。pageSize
:每页显示的数据条数,类型为Number
,默认值为10
。pageSizes
:可供选择的每页数据条数选项,类型为Array
,默认值为[10, 20, 50, 100]
。total
:数据的总条数,类型为Number
,默认值为0
。
事件处理
组件内部定义了多个事件处理函数,用于与父组件进行交互:
handleSelectionChange
:当表格的选择项发生变化时触发,将选中的行数据传递给父组件。handleEdit
:当点击编辑按钮时触发,将当前行的数据传递给父组件,以便进行编辑操作。handleDelete
:当点击删除按钮时触发,将当前行的数据传递给父组件,以便进行删除操作。handleSizeChange
:当用户改变每页显示的数据条数时触发,计算新的查询参数并传递给父组件。handleCurrentChange
:当用户切换到不同的页码时触发,计算新的查询参数并传递给父组件。
自定义序号
为了实现分页情况下序号的正确显示,我们定义了 indexMethod
函数。该函数根据当前页码和每页数据条数,计算出正确的序号。
使用说明
组件页面代码
<template>
<el-table
:data="tableData"
style="width: 100%;"
:border="border"
:highlight-current-row="true"
@selection-change="handleSelectionChange"
>
<el-table-column v-if="selection" type="selection" width="55" :align="align" />
<el-table-column
v-if="showIndex"
type="index"
width="60"
label="序号"
:index="indexMethod"
:align="align"
/>
<el-table-column
v-for="(item, index) in tableConfig"
:key="index"
:label="item.label"
:width="item.width"
:align="align"
>
<template #default="scope">
<slot v-if="item.slot" :name="item.slotName" :row="scope.row">
<el-button type="primary" plain @click="handleEdit(scope.row)"
>编辑</el-button
>
<el-button type="danger" plain @click="handleDelete(scope.row)"
>删除</el-button
>
</slot>
<div v-else-if="item.formatter">
{{ item.formatter(scope.row[item.prop]) }}
</div>
<div v-else>{{ scope.row[item.prop] }}</div>
</template>
</el-table-column>
</el-table>
<el-pagination
v-if="pagination"
class="mt-10"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="myPageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</template>
<script setup>
import { ref } from "vue";
const currentPage = ref(1);
const prop = defineProps({
border: {
Type: Boolean,
default: true,
},
align: {
Type: String,
default: 'center'
},
tableConfig: {
Type: Array,
required: true,
},
tableData: {
Type: Array,
default: () => [],
},
selection: {
Type: Boolean,
default: false,
},
showIndex: {
Type: Boolean,
default: true,
},
pagination: {
Type: Boolean,
default: true,
},
pageSize: {
Type: Number,
default: 10,
},
pageSizes: {
Type: Array,
default: () => [10, 20, 50, 100],
},
total: {
Type: Number,
default: 0,
},
});
const emit = defineEmits(["updateQueryData", "handleSelectionChange","handleEdit","handleDelete"]);
// 自定义序号
const indexMethod = (index) => {
return (currentPage.value - 1) * myPageSize.value + index + 1;
};
// 设置每页条数
const myPageSize = ref(prop.pageSize);
const handleSizeChange = (num) => {
myPageSize.value = num;
currentPage.value = 1;
let params = {
pageNum: (currentPage.value - 1) * myPageSize.value,
pageSize: myPageSize.value,
};
emit("updateQueryData", params, true);
};
// 跳转到该页
const handleCurrentChange = (num) => {
currentPage.value = num;
let params = {
pageNum: (currentPage.value - 1) * myPageSize.value,
pageSize: myPageSize.value,
};
emit("updateQueryData", params, true);
};
const handleSelectionChange = (array) => {
emit("handleSelectionChange", array);
};
// 编辑
const handleEdit = (row) => {
emit("handleEdit", row);
};
// 删除
const handleDelete = (row) => {
emit("handleDelete", row);
};
</script>
<style scoped>
</style>
引入组件
在你的项目中,将封装好的表格组件引入到需要使用的页面中:
<template>
<div>
<MyTable
:border="true"
:align="center"
:tableConfig="tableConfig"
:tableData="tableData"
:selection="true"
:showIndex="true"
:pagination="true"
:pageSize="10"
:pageSizes="[10, 20, 50, 100]"
:total="total"
@updateQueryData="updateQueryData"
@handleSelectionChange="handleSelectionChange"
@handleEdit="handleEdit"
@handleDelete="handleDelete"
/>
</div>
</template>
<script setup>
import MyTable from "@/components/MyTable.vue";
import { ref } from "vue";
const tableConfig = ref([
{ label: "姓名", prop: "name", width: "100" },
{ label: "年龄", prop: "age", width: "80" },
{ label: "操作", slot: true, slotName: "operation", width: "120" }
]);
const tableData = ref([
{ name: "张三", age: 20 },
{ name: "李四", age: 25 },
{ name: "王五", age: 30 }
]);
const total = ref(3);
const updateQueryData = (params, isReset) => {
// 根据参数重新请求数据
};
const handleSelectionChange = (array) => {
console.log("选中的行数据:", array);
};
const handleEdit = (row) => {
console.log("编辑行数据:", row);
};
const handleDelete = (row) => {
console.log("删除行数据:", row);
};
</script>
<style scoped>
</style>
配置表格列
通过 tableConfig
属性配置表格的列信息。每个元素可以包含以下属性:
label
:列名,用于显示在表格头部。prop
:对应数据的属性名,用于从tableData
中获取数据。width
:列宽,设置表格列的宽度。slot
:是否使用插槽,若为true
,则会在该列中渲染自定义插槽内容。slotName
:插槽名,用于在父组件中定义插槽内容。formatter
:数据格式化函数,用于对表格数据进行格式化处理。
数据传递
通过 tableData
属性传递表格展示的数据,通过 total
属性传递数据的总条数。
事件处理
父组件可以通过监听 updateQueryData
、handleSelectionChange
、handleEdit
、handleDelete
等事件,来处理分页、选择、编辑、删除等操作。
总结
通过对 Element Plus 表格组件的二次封装,我们实现了一个通用的表格组件,提高了代码的复用性和开发效率。在实际项目中,可以根据具体需求进一步扩展和优化该组件。希望本文对你有所帮助,如有任何问题,欢迎在评论区留言。