上篇文章对element-plus中的搜索条件el-form进行了封装,下面将对elementplus中的el-table表格进行封装,以支持el-table-column以数组类型输入,且支持类似于vue2中自定义操作的render渲染,vue3中使用动态component和h函数来实现,实现效果如下:
效果图
1组件封装
<template>
<div class='common-table'>
<el-table :data='data' v-bind='$attrs'>
<template v-for="column in computedColumns">
<el-table-column v-if="$slots[column.prop]" v-bind="column" :key="column.prop">
<template #default="scope">
<slot :name="column.prop" v-bind="scope"></slot>
</template>
</el-table-column>
<el-table-column v-else v-bind="column">
<template v-if="column.render" #default="scope">
<component :is="renderColumn(column.render, scope)"></component>
</template>
</el-table-column>
</template>
</el-table>
<el-pagination
v-if='pagination'
@size-change="handleCurrentChange($event, 'size')"
@current-change="handleCurrentChange($event, 'page')"
:current-page='currentPage'
:page-sizes='[10, 20, 50]'
:page-size='pageSize'
layout='total, sizes, prev, pager, next, jumper'
:total='pagination.total'
></el-pagination>
</div>
</template>
<script setup lang='ts'>
import { ref, computed, onMounted, watch, defineComponent } from 'vue'
import { ElTable, ElTableColumn, ElPagination } from 'element-plus'
interface Column {
prop: string;
label: string;
render?: (row: any, column: any, cellValue: any) => any;
}
interface Props {
columns: Column[];
data: {
type: Array<any>,
required: true
},
pagination: {
type: Object
},
onChange: (arg: { offset: number; size: number; total?: number }) => void;
}
const props = defineProps<Props>();
const defaultColumnOption = {
align: 'center',
showOverflowTooltip: true,
};
const currentPage = ref(1);
const pageSize = ref(10);
function renderColumn(renderFunc:Function, scope:any) {
// 调用传入的渲染函数,并传入当前行的数据和其他信息
return defineComponent({
render() {
return renderFunc(scope.row, scope.column, scope.$index, scope);
},
});
}
const computedColumns = computed(() => {
return props.columns.map((column) => ({
...defaultColumnOption,
...column
}))
})
onMounted(() => {
fetchData(currentPage.value, pageSize.value)
});
const fetchData = (page: number, size: number) => {
if (props.onChange) {
props.onChange({
offset: page,
size: size
})
}
}
const handleCurrentChange = (val: number, action: string) => {
if (action === 'page') {
currentPage.value = val
}
if (action === 'size') {
pageSize.value = val
}
fetchData(currentPage.value, pageSize.value)
}
</script>
<style scoped lang="less">
.common-table{
background: white;
padding: 12px;
}
//=========表格相关==========
::v-deep {
.el-table {
//移除最外层下划线
.el-table::before {
height: 0 !important;
}
.el-table__header {
height: 40px !important;
tr {
color: gray;
}
.el-table__cell {
padding: 0;
}
th {
background-color: #ECF6FF !important;
padding: 0;
}
}
.el-table__body {
border-collapse: separate !important;
border-spacing: 0 10px !important;
}
.el-table__row {
height: 70px;
td {
border-top: 1px solid #D9D9D9;
border-bottom: 1px solid #D9D9D9;
color: #6c6c6c;
&:first-child {
border-left: 1px solid #D9D9D9;
}
&:last-child {
border-right: 1px solid #D9D9D9;
}
}
}
}
//去除表头下边框
.el-table th.is-leaf {
border: none !important;
}
}
</style>
2组件使用
封装的组件的使用方法如下:
<PageContent :columns='columns' :data='data' :onChange='onChange'></PageContent>,其中 data:为表格分页数据,columns:为表格头对应的列,pagination:为分页参数,onChange分页事件。
各参数将在如下实例中给出
<template>
<div class='systemdepartment'>
<PageSearch
:config='searchConfig.formItems'
:form='form'
></PageSearch>
<PageContent
:columns='tableColumns'
:data='data'
:onChange='onChange'
:pagination='pagination'
>
<!-- <template v-slot:name><el-button type='primary'>22</el-button></template>-->
</PageContent>
<PageModal ref='modalRef' :modalConfig='modalConfigRef' @submit='submitForm'></PageModal>
</div>
</template>
<script setup lang='ts' name='systemdepartment'>
import { computed, h } from 'vue'
import PageModal from '@/components/PageMain/PageModal/PageModal.vue'
import PageSearch from '@/components/BaseSearch/index.vue'
import PageContent from '@/components/PageMain/PageContent/PageContent.vue'
import searchConfig from '@/views/SystemMain/SystemDepartment/config/search.config'
import useMainStore from '@/store/main/main'
import { usePageModal } from '@/hooks/usePageModal'
import { storeToRefs } from 'pinia'
import modalConfig from './config/modal.config'
import { useRouter } from 'vue-router'
//引入
import FormTableMixin from '@/mixins/form-table.d'
import { postListDataRequest } from '@/service/modules/main/main'
import {ElButton} from "element-plus";
const { modalRef, modalClick, editClick } = usePageModal()
const router = useRouter();
const submitForm = (titleType:string, formObject:object) => {}
const goDetail = (a:object, b:object) => {
router.push('/login');
}
const tableColumns = [
{
label: '序号',
type: 'index',
width: 80
},
{
prop: 'name',
label: '部门名称'
},
{
label: '部门领导',
prop: 'departmentId'
},
{
label: '上级领导',
prop: 'parentId'
},
{
label: '创建时间',
prop: 'createAt'
},
{
label: '操作',
render: (row:object) => {
// 返回一个渲染函数
return h(
'div',
{},
[
h(ElButton, {
type: 'primary',
size: 'small',
onClick: (event) => goDetail(event, row)
}, '查看'),
h(ElButton, {
size: 'small'
}, '删除')
]
)
}
}
];
//使用
const service = async (params:object, _:any) => {
const { data } = await postListDataRequest('users', params)
return {
data: data.list,
total: data.totalCount
}
}
const { form, data, pagination, onChange, params } = FormTableMixin(service, {});
const modalConfigRef = computed(() => {
const mainStore = useMainStore()
const { entriesDepartments } = storeToRefs(mainStore)
modalConfig.formItems.forEach((item) => {
if (item.prop === 'parentId') {
const option = entriesDepartments.value.map((item) => {
return { label: item.name, value: item.id }
})
item.options.push(...option)
}
})
return modalConfig
});
</script>
<style scoped>
.systemdepartment {
border-radius: 7px;
overflow: hidden;
}
</style>