当前位置: 首页> 教育> 培训 > vue3 element-plus 实现 table表格合并单元格 和 多级表头

vue3 element-plus 实现 table表格合并单元格 和 多级表头

时间:2025/7/12 5:47:10来源:https://blog.csdn.net/lzfengquan/article/details/139855659 浏览次数:0次

多级表头

数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。
只需要将el-table-column 放置于el-table-column 中,你可以实现组头。

一般可以直接用官网提供的写法,但是有可能数据会比较多的时候,就需要我们稍微改造一下,方便以后再出现合并的数据,直接可以公用。

合并行或列

多行或多列共用一个数据时,可以合并行或列。
通过给 table 传入span-method方法可以实现合并行或列, 方法的参数是一个对象,里面包含当前行 row、当前列 column、当前行号 rowIndex、当前列号 columnIndex 四个属性。 该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。

效果图如下
在这里插入图片描述
代码
表格的数据布局 index.vue

<!-- 架型匹配与拆分记录 -->
<template><el-table:data="tableData"style="width: 100%"height="100%"class="record-supply":row-key="getRowKeys":header-cell-style="{background: '#fafafa',fontSize: '14px',height: '40px',fontWeight: 'normal',boxSizing: 'border-box',color: '#707070'}"ref="myTable":span-method="spanMethod"@cell-mouse-enter="handleCellMouseEnter"@cell-mouse-leave="handleCellMouseLeave"><el-table-columnv-for="item in columns":key="item.id":label="item.label":align="item.align":width="item.width":label-class-name="item?.labelClass":class-name="item?.className"><!-- 如果有子列,递归渲染子列 --><template v-if="item.children && item.children.length > 0"><template v-for="child in item.children" :key="child.id"><el-table-columnv-if="child?.formatValue":label="child.label":prop="child.prop":width="child.width":align="child.align":label-class-name="child?.labelClass":class-name="child?.className":formatter="child?.formatValue"/><el-table-columnv-elsefixed="right":label="child.label":prop="child.prop":width="child.width":align="child.align":label-class-name="child?.labelClass":class-name="child?.className"><template #default="scope"><div v-if="child.prop === 'projectName'"><div class="link">{{scope.row?.projectName}}</div><div class="grey">{{scope.row?.projectNo ?? scope.row?.projectCode}}</div></div><div v-if="child.prop === 'matchTime'"><div style="word-break: break-word; white-space: normal">{{ scope.row.matchTime ?? '--' }}</div></div><!-- 录入架型数据 支架型号/类型 --><div v-if="child.prop === 'supplyModel'"><div class="link">{{ scope.row.supplyModel ?? '--' }}</div><div class="grey" v-if="scope.row.supplyFirstType || scope.row.supplySecondType">{{ GET_SUPPORT_TYPE(scope.row.supplyFirstType) }} > {{ GET_SUPPORT_SECOND_TYPE_NAME(scope.row.supplySecondType) }}</div></div><!-- ERP匹配数据 支架型号/类型 --> <div v-if="child.prop === 'model'"><div class="link">{{ scope.row.model }}</div><!-- ERP 匹配数据 --><div class="grey">{{ GET_SUPPORT_SECOND_TYPE_NAME(scope.row.secondDeviceType) }} </div></div></template></el-table-column></template></template></el-table-column></el-table>
</template><script setup lang="ts">
// import dayjs from 'dayjs'
import {GET_SUPPORT_TYPE,GET_SUPPORT_SECOND_TYPE_NAME
} from '@/views/project/device/components/config'
const props = defineProps({columns: { type: Array<any>, default: [] },tableData: { type: Array<any>, default: [] }
})
const { columns, tableData } = toRefs(props)
const getRowKeys = (row: any) => {return row.id
}
const megre = reactive(['projectNo', // 项目编码'expectedDeliveryTime', // 排产月'contractNo', // 合同号'matchTime', // 匹配日期'supplyModel', // 支架型号/类型'supplySingleWeight', // 单重'supplyDeviceCount', // 数量'supplyTotalWeight' // 总吨位
])
const spanArr = computed(() => {const spanArr: any = {}megre.forEach((m) => {spanArr[m] = { spanArr: [], pos: 0 }})tableData.value.forEach((row: any, i: any) => {megre.forEach((m: any) => {if (i == 0) {spanArr[m].spanArr.push(1)spanArr[m].pos = 0} else {// 批次号相同且项目编码相同的let flag = row.batchNo === tableData.value[i - 1].batchNo && row.projectNo == tableData.value[i - 1].projectNo//根据项目编码 合并单元格 一样则合并  为空||不同的情况不合并if (flag && tableData.value[i - 1].projectNo) {if (row[m] === tableData.value[i - 1][m]) {// 相等的合并+1spanArr[m].spanArr[spanArr[m].pos] += 1spanArr[m].spanArr.push(0)} else {// 不相等push 1,并且可修改下标指向spanArr[m].spanArr.push(1)spanArr[m].pos = i}} else {spanArr[m].spanArr.push(1)spanArr[m].pos = i}}})})return spanArr
})const spanMethod = ({ row, column, rowIndex, columnIndex }: any) => {// 合并单元格 indexOfconst spanArr1: any = spanArr.valueswitch (columnIndex) {case 0:return {rowspan: spanArr1.projectNo.spanArr[rowIndex],colspan: spanArr1.projectNo.spanArr[rowIndex] == 0 ? 0 : 1}case 1:return {rowspan: spanArr1.projectNo.spanArr[rowIndex],colspan: spanArr1.projectNo.spanArr[rowIndex] == 0 ? 0 : 1}case 2:return {rowspan: spanArr1.contractNo.spanArr[rowIndex],colspan: spanArr1.contractNo.spanArr[rowIndex] == 0 ? 0 : 1}case 3:return {rowspan: spanArr1.matchTime.spanArr[rowIndex],colspan: spanArr1.matchTime.spanArr[rowIndex] == 0 ? 0 : 1}case 4:return {rowspan: spanArr1.supplyModel.spanArr[rowIndex],colspan: spanArr1.supplyModel.spanArr[rowIndex] == 0 ? 0 : 1}case 5:return {rowspan: spanArr1.supplySingleWeight.spanArr[rowIndex],colspan: spanArr1.supplySingleWeight.spanArr[rowIndex] == 0 ? 0 : 1}case 6:return {rowspan: spanArr1.supplyDeviceCount.spanArr[rowIndex],colspan: spanArr1.supplyDeviceCount.spanArr[rowIndex] == 0 ? 0 : 1}case 7:return {rowspan: spanArr1.supplyTotalWeight.spanArr[rowIndex],colspan: spanArr1.supplyTotalWeight.spanArr[rowIndex] == 0 ? 0 : 1}default:return {rowspan: 1,colspan: 1}}
}let currentIndex = ref('')
let currentColumnIndex = ref('')
const handleCellMouseEnter = (row: any, column: any) => {//鼠标移入后赋值currentIndex.value = row.projectNo //row.productCode是行相同的标志currentColumnIndex.value = column.property //获取列的标题名
}
const handleCellMouseLeave = () => {//鼠标移走后置空currentIndex.value = ''currentColumnIndex.value = ''
}// // 行的颜色设置 :row-class-name="tableRowClassName" :cell-style="cellStyle"
// const tableRowClassName = ({ row }: any) => {
//   let flag = row.projectNo == currentIndex.value && megre.includes(currentColumnIndex.value)
//   return flag ? 'quotatemplate-my-hover-row' : ''
// }// // 鼠标移入除合并单元格的其它单元格,这时候需要单独一行展示。
// const cellStyle = ({ row, column, rowIndex, columnIndex }: any) => {
//   let flag =
//     row.projectNo == currentIndex.value &&
//     currentColumnIndex.value &&
//     megre.includes(currentColumnIndex.value)
//   return flag ? { background: '#f4f6fa' } : { '': '' }
// }
</script><style scoped lang="scss">
.header-nav {display: flex;align-items: center;height: 40px;border: 1px solid #ebeef5;background: #fafafa;border-bottom: none;border-right: none;& > div {flex: 1;border-right: 1px solid #ebeef5;text-align: center;}
}
:deep(.record-supply) {.el-table__border-left-patch {width: 0;}.column-border {border-left: 1px solid #ebeef5;}.border-none {border-right: none;}.border-right {border-right: 1px solid #ebeef5;}.column-height {height: 70px;}.el-table__cell {.cell {padding-left: 8px;}}
}
.edit-style {color: #3076fe;& > div {cursor: pointer;}
}
:deep(.el-table--border::before),
:deep(.el-table--border::after) {width: 0px;
}
.link {// cursor: pointer;color: #262626;overflow: hidden;text-overflow: ellipsis;
}
.grey {color: #a3a3a3;
}
</style>
<style>
/* 移除划过时表格的背景色 || 自行设置划过的背景色 || 不写下方样式将默认颜色 */
.record-supply.el-table .quotatemplate-my-hover-row {background: #f4f6fa !important;
}
</style>

数据的映射config.ts 页面

import dayjs from 'dayjs'
// 架型匹配与拆分记录
export const splitRecordColumns = (): any[] => [{id: 1,label: '录入架型数据',width: '',labelClass: 'column-border',className: '',align: 'center',children: [{id: 11,label: '项目名称/编码',prop: 'projectName',width: '172',align: ''},{id: 12,label: '排产月',prop: 'expectedDeliveryTime',width: '80',align: 'center',formatValue: (row: any) =>row.expectedDeliveryTime ? dayjs(row.expectedDeliveryTime).format('YYYY-MM') : '--'},{id: 13,label: '合同号',prop: 'contractNo',width: '160',labelClass: 'column-border',align: 'center',formatValue: (row: any) => row.contractNo || '--'},{id: 14,label: '匹配时间',prop: 'matchTime',width: '100',align: ''},{id: 15,label: '支架型号/类型',prop: 'supplyModel',width: '170',align: ''},{id: 16,label: '单重',prop: 'supplySingleWeight',width: '70',align: 'center',formatValue: (row: any) => (row.supplySingleWeight ? row.supplySingleWeight + '吨' : '--')},{id: 17,label: '数量',prop: 'supplyDeviceCount',width: '70',align: 'center',formatValue: (row: any) => (row.supplyDeviceCount ? row.supplyDeviceCount + '架' : '--')},{id: 18,label: '总吨位',prop: 'supplyTotalWeight',width: '90',align: 'center',formatValue: (row: any) => (row.supplyTotalWeight ? row.supplyTotalWeight + '吨' : '--')}]},{id: 2,label: 'ERP匹配数据',width: '',labelClass: '',className: '',align: 'center',children: [{id: 21,label: '排产月',prop: 'planProduceMonth',width: '80',align: '',formatValue: (row: any) =>row.planProduceMonth ? dayjs(row.planProduceMonth).format('YYYY-MM') : '--'},{id: 22,label: '施工号',prop: 'constructionNo',width: '110',align: '',formatValue: (row: any) => row.constructionNo || '--'},{id: 23,label: '支架型号/类型',prop: 'model',width: '170',align: ''},{id: 24,label: '单重',prop: 'singleWeight',width: '70',align: '',formatValue: (row: any) => (row.singleWeight ? row.singleWeight + '吨' : '--')},{id: 25,label: '数量',prop: 'deviceCount',width: '70',align: '',formatValue: (row: any) => (row.deviceCount ? row.deviceCount + '架' : '--')},{id: 26,label: '总吨位',prop: 'totalWeight',width: '90',align: '',formatValue: (row: any) => (row.totalWeight ? row.totalWeight + '吨' : '--')},{id: 27,label: '交审日期',prop: 'transferDate',width: '90',align: '',formatValue: (row: any) =>row.transferDate ? dayjs(row.transferDate).format('MM月DD日') : '--'},{id: 28,label: '备注',prop: 'remark',labelClass: 'border-right',className: 'border-none column-height',width: '',align: '',formatValue: (row: any) => row.remark || '--'}]}
]

注意的是,可能需求不同,但是方法是一样的。只需要把方法中的值替换即可实现公用。

如下图:
注意的项是 要和并的字段不一样,我们需要单独去设置;spanMethod 方法会根据 设定的 merge 值去合并;
spanArr 方法执行计算属性,添加我们的判断条件。需要满足需求条件才会更新数据。
在这里插入图片描述
这样就结束了。
展示最后的效果
在这里插入图片描述
在这里插入图片描述
满足条件的进行合并,不满足的则是单独一行展示

关键字:vue3 element-plus 实现 table表格合并单元格 和 多级表头

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: