最近在做PC端需求的时候,需要把首列中相邻的同名称单元格合并。
我看了一下elementPlus官网中的table表格,span-method可以实现单元格合并。
我们先看一下官网的例子:
合并行或列
多行或多列共用一个数据时,可以合并行或列。
通过给 table 传入span-method方法可以实现合并行或列, 方法的参数是一个对象,里面包含当前行 row、当前列 column、当前行号 rowIndex、当前列号 columnIndex 四个属性。 该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。
rowspan:合并几行
colspan:合并几列
<template> <div> <el-table :data="tableData" :span-method="arraySpanMethod" border style="width: 100%" > <el-table-column prop="id" label="ID" width="180" /> <el-table-column prop="name" label="Name" /> <el-table-column prop="amount1" sortable label="Amount 1" /> <el-table-column prop="amount2" sortable label="Amount 2" /> <el-table-column prop="amount3" sortable label="Amount 3" /> </el-table> <el-table :data="tableData" :span-method="objectSpanMethod" border style="width: 100%; margin-top: 20px" > <el-table-column prop="id" label="ID" width="180" /> <el-table-column prop="name" label="Name" /> <el-table-column prop="amount1" label="Amount 1" /> <el-table-column prop="amount2" label="Amount 2" /> <el-table-column prop="amount3" label="Amount 3" /> </el-table> </div> </template> <script lang="ts" setup> import type { TableColumnCtx } from 'element-plus' interface User { id: string name: string amount1: string amount2: string amount3: number } interface SpanMethodProps { row: User column: TableColumnCtx<User> rowIndex: number columnIndex: number } const arraySpanMethod = ({ row, column, rowIndex, columnIndex, }: SpanMethodProps) => { if (rowIndex % 2 === 0) { if (columnIndex === 0) { return [1, 2] // // 合并1行 合并2列 } else if (columnIndex === 1) { return [0, 0] } } } const objectSpanMethod = ({ row, column, rowIndex, columnIndex, }: SpanMethodProps) => { if (columnIndex === 0) { if (rowIndex % 2 === 0) { // 2、4、6、8...... return { rowspan: 2, // 合并2行 colspan: 1, // 合并1列 } } else { return { rowspan: 0, colspan: 0, } } } } const tableData: User[] = [ { id: '12987122', name: 'Tom', amount1: '234', amount2: '3.2', amount3: 10, }, { id: '12987123', name: 'Tom', amount1: '165', amount2: '4.43', amount3: 12, }, { id: '12987124', name: 'Tom', amount1: '324', amount2: '1.9', amount3: 9, }, { id: '12987125', name: 'Tom', amount1: '621', amount2: '2.2', amount3: 17, }, { id: '12987126', name: 'Tom', amount1: '539', amount2: '4.1', amount3: 15, }, ] </script>
复制
效果如下:
好了,官网例子看过,来看看我在实际项目中是怎么应用的。
需要处理的数据如下:
let data = [ { firstName: '基本证照', code: '001', secondName: '营业执照', sort: '30', fileList: [ { id: '1', name: '营业执照照片' } ] }, { firstName: '基本证照', code: '002', secondName: '身份证照', sort: '40', fileList: [ { id: '2', name: '身份证照照片' } ] }, { firstName: '现场照片', code: '003', secondName: '公司前台照', sort: '50', fileList: [ { id: '3', name: '公司前台照照片' } ] }, { firstName: '现场照片', code: '004', secondName: '公司工位照', sort: '60', fileList: [ { id: '4', name: '公司工位照照片' } ] }, { firstName: '经营证明', code: '005', secondName: '工厂生产照', sort: '70', fileList: [ { id: '5', name: '工厂生产照照片' } ] } ]
复制
需要展示的效果是:
首列中只有三行(基本证照、现场照片、经营证明)
也就是说 基本证照、现场照片这个两个首列需要合并两行
封装的函数如下,函数中都是注释,对函数中的定义和字段做了详细的说明。
// 合并单元格规则(data为表格数据,cateName为合并字段的名称)这个函数的作用是对首列中的行进行合并 function objSpanMethod({ row, column, rowIndex, columnIndex }, data, cateName) { // 非首列的数据都返回,不往下进行 if (columnIndex !== 0) { return } let arrLength = [] // 存放secondName对应的数据数组长度 let cateRows = [] // 存放起始合并行以及合并行数 data.reduce((preValue, curValue, index, array) => { if (index == 0 || preValue[cateName] != curValue[cateName]) { arrLength.push(1) } else { arrLength[arrLength - 1]++ } return curValue }, data[0]) // 获取存放起始合并行以及合并行数 arrLength.reduce((pre, cur, index, value) => { // pre指的是上一次计算过后的prev + cur这个值 cateRows.push({ rowIndex: prev, rowspan: cur }); // rowIndex指的是从第几行开始合并,rowspan指的是合并几行 return prev + cur }, 0) let intRowSpan = 0; for (let i = 0; i < arrLength.length; i++) { if (cateRows[i].rowIndex == rowIndex) { intRowSpan = cateRows[i].rowspan; break; } } return { // 当渲染执行到某一行的首列时,或者执行到首列时,对其中的行进行渲染时,例如渲染到第四行时,发现rowspan为3时, // 那就是首列中从第四行开始合并,合并3行,四、五、六这三行合并为一行。 rowspan: intRowSpan, colspan: intRowSpan == 0 ? 0 : 1 // 如果不合并行,就返回0,说白了就不合并 } }
复制
具体的使用请看以下完整的代码:
<template> <div class="table"> <el-table :data="data" :span-method="(param) => objSpanMethod(param, data, 'firstName')" > <el-table-colum prop="firstName" label="资料分类" width="150" /> <el-table-colum prop="secondName" label="资料名称" /> <el-table-colum prop="fileList" label="已上传资料"> <template #default="{ row }"> <p v-for="(item,index)" in row.fileList :key="item?.name + index"> <span> {{ item?.name }} </span> </p> </template> </el-table-colum> </el-table> </div> </template> <script setup> // data是接口请求回来的数据 // 数据如下: let data = [ { firstName: "基本证照", code: "001", secondName: "营业执照", sort: "30", fileList: [ { id: "1", name: "营业执照照片", }, ], }, { firstName: "基本证照", code: "002", secondName: "身份证照", sort: "40", fileList: [ { id: "2", name: "身份证照照片", }, ], }, { firstName: "现场照片", code: "003", secondName: "公司前台照", sort: "50", fileList: [ { id: "3", name: "公司前台照照片", }, ], }, { firstName: "现场照片", code: "004", secondName: "公司工位照", sort: "60", fileList: [ { id: "4", name: "公司工位照照片", }, ], }, { firstName: "经营证明", code: "005", secondName: "工厂生产照", sort: "70", fileList: [ { id: "5", name: "工厂生产照照片", }, ], }, ]; // 合并单元格规则(data为表格数据,cateName为合并字段的名称)这个函数的作用是对首列中的行进行合并 function objSpanMethod({ row, column, rowIndex, columnIndex }, data, cateName) { // 非首列的数据都返回,不往下进行 if (columnIndex !== 0) { return; } let arrLength = []; // 存放secondName对应的数据数组长度 let cateRows = []; // 存放起始合并行以及合并行数 data.reduce((preValue, curValue, index, array) => { if (index == 0 || preValue[cateName] != curValue[cateName]) { arrLength.push(1); } else { arrLength[arrLength - 1]++; } return curValue; }, data[0]); // 获取存放起始合并行以及合并行数 arrLength.reduce((pre, cur, index, value) => { // pre指的是上一次计算过后的prev + cur这个值 cateRows.push({ rowIndex: prev, rowspan: cur }); // rowIndex指的是从第几行开始合并,rowspan指的是合并几行 return prev + cur; }, 0); let intRowSpan = 0; for (let i = 0; i < arrLength.length; i++) { if (cateRows[i].rowIndex == rowIndex) { intRowSpan = cateRows[i].rowspan; break; } } return { // 当渲染执行到某一行的首列时,或者执行到首列时,对其中的行进行渲染时,例如渲染到第四行时,发现rowspan为3时, // 那就是首列中从第四行开始合并,合并3行,四、五、六这三行合并为一行。 rowspan: intRowSpan, colspan: intRowSpan == 0 ? 0 : 1, // 如果不合并行,就返回0,说白了就不合并 }; } </script> <style> </style>
复制
这样就完全实现了首列中行的合并。总结这些呢,主要是记录下rowspan:合并几行
colspan:合并几列这个规则,还是就是合并行中对于数据的处理。
好记性不如烂笔头,虽然当时明白的很好,但是还是总结记录下来最好。