最近在做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:合并几列这个规则,还是就是合并行中对于数据的处理。
好记性不如烂笔头,虽然当时明白的很好,但是还是总结记录下来最好。