vue3封装Element Plus table表格组件
支持绝大部分Element Plus原有设置属性,支持分页,支持动态适配高度
效果展示
组件代码:
<template>
<div class="table-wrap" ref="tableWrap">
<el-table
class="w100 h100"
:data="tableInfo.tableData"
:height="tableHeight"
v-bind="attrs"
>
<!-- 动态生成列 -->
<template v-for="(item, index) in columns" :key="index">
<!-- 选择列 -->
<el-table-column
v-if="item.type == 'selection'"
type="selection"
v-bind="item"
>
</el-table-column>
<!-- 普通列 -->
<el-table-column v-else-if="!item.subColumns" v-bind="item">
<template #default="scope">
<slot :name="item.prop" :scope="scope">
{{ scope.row[item.prop] }}
</slot>
</template>
</el-table-column>
<!-- 嵌套列 -->
<el-table-column v-else v-bind="item">
<el-table-column
v-for="(child, childIndex) in item.subColumns"
:key="childIndex"
v-bind="child"
>
<template #default="scope">
<slot :name="child.prop" :scope="scope">
{{ scope.row[child.prop] }}
</slot>
</template>
</el-table-column>
</el-table-column>
</template>
</el-table>
<el-pagination
:page-sizes="pageSizes"
:current-page="page.currentPage"
:page-size="page.pageSize"
background
layout="total, sizes, prev, pager, next, jumper"
:total="tableInfo.total"
@size-change="
handleChangePage({
currentPage: page.currentPage,
pageSize: $event,
})
"
@current-change="
handleChangePage({
currentPage: $event,
pageSize: page.pageSize,
})
"
/>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
// Props 接收
const { tableInfo, columns, pageSizes, ...props } = defineProps({
tableInfo: {
type: Object,
default: () => {
return {
tableData: [],
total: 0,
};
},
},
columns: {
type: Array,
default: () => [],
},
pageSizes: {
type: Array,
default: () => [10, 25, 50, 100],
},
});
const emit = defineEmits(["current-change"]);
// 获取其他绑定属性
const { attrs } = getCurrentInstance();
// 引用
const tableWrap = ref(null);
const tableHeight = ref(50); // 默认高度
let resizeObserver = null;
//分页
const page = ref({
currentPage: 1,
pageSize: 10,
});
//函数
const handleChangePage = ({ currentPage, pageSize }) => {
page.value.currentPage = currentPage;
page.value.pageSize = pageSize;
emit("current-change", { currentPage, pageSize});
};
// 动态计算表格高度
const initResizeObserver = () => {
if (!tableWrap.value) return;
// 32是分页高度 10和分页的间隔
resizeObserver = new ResizeObserver(() => {
tableHeight.value = tableWrap.value.offsetHeight - 32 - 10 || 500;
});
resizeObserver.observe(tableWrap.value);
};
// 生命周期
onMounted(() => initResizeObserver());
onUnmounted(() => resizeObserver?.disconnect());
</script>
<style scoped lang="scss">
.table-wrap {
width: 100%;
height: 100%;
overflow: auto; /* 根据需求适配 */
display: flex;
flex-direction: column;
gap: 10px;
}
</style>
使用方法:
注意由于表格通过ref="tableWrap"获取的高度,然后ref="tableWrap"设置的高度百分百,所以在使用组件的时候注意组件的外层高度如下方的class="universalTable h100"。
但设置双层表头的时候注意需要把二级表头放在subColumns属性中。
table原生属性可直接加在组件上例如“ :border="true"”的写法,属性方法都可支持
<template>
<div class="universalTable h100">
<universalTable
:border="true"
:columns="columns"
:tableInfo="tableInfo"
ref="refTable"
@current-change="handleCurrentChange"
>
<template #name="{ scope }">
<span>{{ scope.row.name }}</span>
</template>
</universalTable>
</div>
</template>
<script setup name="Index">
import { ref, reactive, nextTick } from "vue";
//表头数据
const columns = ref([
{
type: "selection",
},
{
label: "测试",
subColumns: [
{
prop: "date",
label: "Date",
width: 100,
},
],
},
{
prop: "name",
label: "Name",
width: 120,
},
{
prop: "address",
label: "Address",
},
]);
//列表数据
const tableInfo = ref({
tableData: [
{
date: "2016-05-03",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-02",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-04",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-01",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
],
total: 100,
});
//分页数据
const page = ref({
currentPage: 1,
pageSize: 10,
});
//获取分页数据
const handleCurrentChange = ({ currentPage, pageSize }) => {
page.value.currentPage = currentPage;
page.value.pageSize = pageSize;
};
</script>
<style scoped lang="scss">
.universalTable {
}
</style>