这篇文章主要介绍了elementplus怎么实现多级表格的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇elementplus怎么实现多级表格文章都会有所收获,下面我们一起来看看吧。
想要实现的效果
总共四级 前三级是表格 第四级使用图片展示; 看了一下官网 计划使用官网的树形结构, 但是发现并不能满足最后一个是图片形式的展示
最后利用了表格的expand;
在过程中主要需要解决的问题有:vue3 递归使用组件;递归处理数据;展开全部级。
递归处理数据
首先需要处理一下数据,把他们弄成字段一致的,如果后端处理过,前端也会需要处理一下,用于前端自己新增使用的字段 ,我这边 新增了三个字段
disableExpand: 用于我的展开表格 单行能不能展开
id: 后端没有给id字段 用于唯一标识
level: 判断当前数据是第几级数据
const getOverviewList = async () => { if (!searchParams.value.train_type_id) { return; } const resp = await Pepper.get('/api/match/detail', { params: searchParams.value }); overviewTotal.value = resp.data.list.length; overviewList.value = handleOverviewList(resp.data.list); }; const handleOverviewList = (data: OverviewListModel[], listLevel = 1) => { const result: OverviewListModel[] = data.map((item, index) => { return { ...item, // 新增字段 disableExpand: !!item.sub_number, level: listLevel, id: listLevel + '-' + index, // 处理list list: item.list && item.list.length ? handleOverviewList(item.list as OverviewListModel[], listLevel + 1) : [] }; }); return result; };
递归调用组件
因为字段一致所以我使用的是同一个组件,需要说明的是 vue3使用自己组件的时候直接使用即可
在外层:传入所有的data
<overview-table ref="overviewTableRef" :total="overviewTotal" :data="overviewList" />
在OverviewTable组件中 直接使用OverviewTable就可;下面这个包括展开所有级的代码
展开所有级 利用@expand=“handleExpand” 修改expandKeys即可
<template> <div> <expand-table ref="tableRef" :data="data" :total="total" :pageParams="pageParams" v-model:expandRowKeys="expandKeys" v-bind="$attrs" @oneClick="rowClick" @expand="handleExpand" > <template #expand="{ row }"> <overview-table :ref="el => setOverviewDetailRef(el, row.id)" v-if="row.level !== 3" :data="row.list" :total="row.list.length" :show-header="false" :height="2000" :table-level="row.level + 1" /> <overview-table-detail v-else :data="row.list" @openDialog="openDialog" /> </template> <el-table-column prop="name" min-width="10%" label="数据类型" /> .... <el-table-column prop="sub_number" min-width="10%" label="包含下级数" > <template #default="{ row }"> <span :class="!row.sub_number ? 'no-sub' : ''">{{ row.sub_number }}</span> </template> </el-table-column> <operation-column min-width="10%" :operationOptions="operationOptions" /> </expand-table> <image-detail-dialog :showDeleteBtn="false" ref="imageDetailDialogRef" /> </div> </template> <script setup lang="ts"> import { computed, ref, inject, nextTick } from 'vue'; import ExpandTable from '@/components/table/ExpandTable.vue'; import OverviewTableDetail from './OverviewTableDetail.vue'; import ImageDetailDialog from '../../original/stop/ImageDetailDialog.vue'; import OperationColumn, { OperationOptionModel } from '@/components/table/OperationColumn.vue'; import { PageAware } from '@/model'; import { ConfigModel } from 'public/config'; import { OverviewListModel } from '@/model/registration'; import { PhotoListModel } from '@/model/original'; const props = withDefaults( defineProps<{ data: OverviewListModel[]; total: number; tableLevel?: number; }>(), { data: () => [], tableLevel: 1 } ); const pageParams = ref<PageAware>({ page_no: 1, page_size: (inject('global') as ConfigModel).registration.registrationLimit }); const tableRef = ref<InstanceType<typeof ExpandTable>>(); const overviewDetailRefs = ref<any>({}); const imageDetailDialogRef = ref<InstanceType<typeof ImageDetailDialog>>(); const expandKeys = ref<string[]>([]); const operationOptions = computed<OperationOptionModel[]>(() => { return [ { icon: 'icon-upload', title: '上传', hidden: props.tableLevel !== 1, onClick: () => {} }, { icon: 'icon-compute', title: '计算', hidden: props.tableLevel !== 2, disabled: (row: OverviewListModel) => { return row.state !== '待计算'; }, onClick: () => {} } ]; }); // 动态ref const setOverviewDetailRef = (el: any, id: number) => { if (el) { overviewDetailRefs.value[id] = el; } }; // 打开弹窗 const openDialog = (index: any, data: PhotoListModel[]) => { imageDetailDialogRef.value?.open(index, data); }; // 单击展开/关闭 const rowClick = (row: OverviewListModel) => { if (expandKeys.value.includes(row.id)) { tableRef.value?.closeRowExpansion(row); } else { expandKeys.value.push(row.id); } }; // 展开全部 const handleExpand = (ids: number[] | string[]) => { // 情况1:一级全部展开 点击其他的时候 只展开下一级 // const handleExpand = (ids: number[] | string[], autoExpand) => { // autoExpand.value = autoExpandEd ? autoExpandEd : props.tableLevel === 1; // if (!autoExpand.value) { // return; // } // 情况3:点击一级 只展开到三级 // if (props.tableLevel !== 1) { // return; // } ids.forEach(async id => { await nextTick(); const stopOverviewDetailRef = overviewDetailRefs.value[id]; if (stopOverviewDetailRef) { await stopOverviewDetailRef?.openRowExpansion(); } }); }; const openRowExpansion = () => { //情况1:一级全部展开 点击其他的时候 只展开下一级 // const ids = (props.data as OverviewListModel[]).map(i => i.id); // handleExpand(ids, true); // 情况2:点击任何一级 他下面的都展开 props.data.map(item => { if (!item.disableExpand) { return; } if (!expandKeys.value.includes(item.id)) { expandKeys.value.push(item.id); } }); }; const reset = () => { // 重新搜索的时候 关闭展开的 tableRef.value?.closeAllExpand(); expandKeys.value = []; }; defineExpose({ reset, expandKeys, openRowExpansion }); </script> <style lang="scss" scoped> :deep(.el-table__expanded-cell[class*='cell']) { padding: 0; } :deep(.el-button + .el-button) { margin-left: 0; } .no-sub { color: #b9bdc9; } // 防止弹框样式有问题 :deep(.el-table .el-table__row) { position: relative; z-index: 0; } </style>