vue3封装element-plus的Table表格
# 新建 Table.vue
src/components/Table.vue
<script setup lang="ts">
import { reactive, useSlots, isProxy } from "vue";
import { Delete, Edit } from '@element-plus/icons-vue';
// 【接口】通用设置key
interface IKey {
[key: string]: any;
}
// 【接口】table表格模型
interface ITableModel {
label: string;
key: string;
width?: number;
value?: string;
}
// 【接口】接受传参字段
interface IProps {
tableModels?: ITableModel[];
data: object[];
total: number;
showEditBtn?: boolean;
showDeleteBtn?: boolean;
operationsWidth?: number;
}
// 初始化默认参数
const props = withDefaults(defineProps<IProps>(), {
total: 0,
showEditBtn: true,
showDeleteBtn: true,
operationsWidth: 200
});
// 插槽对象
const slots = useSlots();
// 事件
const emit = defineEmits<{
(e: "handleEdit", data: object, index: number): void;
(e: "handleDelete", data: object, index: number): void;
(e: "handlePagination", data: object): void;
}>();
// 点击了编辑
const handleEdit = (data: object, index: number) => {
emit('handleEdit', data, index);
};
// 点击了删除
const handleDelete = (data: object, index: number) => {
emit('handleDelete', data, index);
};
// 替换表格数据
const replaceColumnData = (data: object, key: string) => {
let value = '';
if (isProxy(data)) {
const newData = Object.assign({}, data);
const keys = key.split('.');
// 递归次数
const count = keys.length;
// 当前递归次数
let i = 0;
const getValue = (obj: IKey) => {
if (i < count) {
const index = i;
i++;
value = obj[keys[index]];
getValue(obj[keys[index]]);
}
}
getValue(newData);
}
return value;
};
// 分页
const page = reactive({
currentPage: 1,
pageSize: 10,
})
// 改变了分页条数
const handleSizeChange = (val: number) => {
page.pageSize = val;
handlePagination();
}
// 改变了页数
const handleCurrentChange = (val: number) => {
page.currentPage = val;
handlePagination();
}
// 改变了分页
const handlePagination = () => {
emit('handlePagination', page);
}
</script>
<template>
<el-table :data="data" stripe :border="true" table-layout="fixed" style="width: 100%">
<el-table-column v-for="tableModel in props.tableModels" :key="tableModel.key" :prop="tableModel.key"
:label="tableModel.label" :width="tableModel.width">
<template #default="scope">
<slot v-if="slots[tableModel.key]" :name="tableModel.key" v-bind="scope.row"></slot>
<span v-else-if="tableModel.value">
{{ replaceColumnData(scope.row, tableModel.value) }}
</span>
<span v-else>
{{ scope.row[tableModel.key] }}
</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" :width="operationsWidth" v-if="operationsWidth">
<template #default="scope">
<el-button link type="primary" :icon="Edit" @click="handleEdit(scope.row, scope.$index)" v-if="showEditBtn">编辑
</el-button>
<el-popconfirm title="确定要删除吗?" @confirm="handleDelete(scope.row, scope.$index)" confirm-button-text="确定"
cancel-button-text="再想想">
<template #reference>
<el-button link type="danger" :icon="Delete" v-if="showDeleteBtn">删除
</el-button>
</template>
</el-popconfirm>
<slot name="operations" v-bind="scope.row"></slot>
</template>
</el-table-column>
</el-table>
<el-pagination class="c-pagination" v-model:currentPage="page.currentPage" v-model:page-size="page.pageSize"
:page-sizes="[10, 20, 50, 100, 200, 500]" background layout="total, sizes, prev, pager, next, jumper" :total="total"
hide-on-single-page @size-change="handleSizeChange" @current-change="handleCurrentChange" />
</template>
<style scoped>
.c-pagination {
margin-top: 20px;
}
</style>
# 参数说明
属性 | 描述 | 默认值 | 必需 |
---|---|---|---|
tableModels | 表格配置 | [] | 是 |
data | 表单数据 | [] | 是 |
total | 数据条数 | 0 | 是 |
showEditBtn | 是否显示编辑按钮 | true | 否 |
showDeleteBtn | 是否显示删除按钮 | true | 否 |
operationsWidth | 操作列宽度 | 200 | 否 |
# tableModels
属性 | 描述 | 必需 |
---|---|---|
label | 表格表头 | 是 |
key | 表格对应的字段 | 是 |
width | 列宽度 | 否 |
value | 字段实际路径 | 否 |
# 事件
事件 | 描述 | 返回值 |
---|---|---|
@handleEdit | 点击【编辑】按钮事件 | 该行的值 |
@handleDelete | 点击【删除】按钮事件 | 该行的值 |
@handlePagination | 改变【分页】事件 | 当前页、每页条数 |
# 使用
src/views/home.vue
<script setup lang="ts">
import { reactive } from 'vue';
import Table from './Table.vue';
const table = reactive({
tableModels: [
{
label: '数据标识',
key: 'id',
width: 200,
},
{
label: '账户',
key: 'name',
width: 200,
},
{
label: '密码',
key: 'password',
width: 200,
},
{
label: '地址',
key: 'address',
width: 200,
value: 'info.address'
},
{
label: '手机号',
key: 'phone',
width: 200,
},
],
data: [],
total: 20
});
const arr: any = [];
for (let i = 0; i < 10; i++) {
const data = {
id: i,
name: '123',
password: '123',
info: {
address: '中国'
},
phone: '10086'
}
arr.push(data);
}
table.data = arr;
const handleEdit = (data: object, index: number) => {
console.log('点击了编辑按钮 => ', data, index);
}
const handleDelete = (data: object, index: number) => {
console.log('点击了删除按钮 => ', data, index);
}
const handlePagination = (data: any) => {
const { currentPage, pageSize, } = data;
console.log('改变了分页 => ', { currentPage, pageSize, });
}
</script>
<template>
<p>================================</p>
<Table :tableModels="table.tableModels" :data="table.data" :total="table.total" @handleEdit="handleEdit"
@handleDelete="handleDelete" @handlePagination="handlePagination">
<!-- 自定义列【phone】字段 -->
<template v-slot:phone="scope">
<el-tag>{{ scope.phone }}</el-tag>
</template>
</Table>
<p>================================</p>
</template>
<style scoped>
</style>
# 效果图
版权声明:本文为weixin_42863549原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。