Element UI官方文档中有说明使用span-method去实现el-table的列合并功能,但是有时候我们需要根据接口数据动态的设置列的合并,同样是使用span-method实现,只是需要自己处理好合并逻辑。
实现代码如下
<template>
<div class="container">
<el-table
:data="tableData"
:span-method="objectSpanMethod"
border
style="width: 100%"
>
<el-table-column prop="name" label="姓名" />
<el-table-column prop="age" label="年龄" />
<el-table-column prop="sex" label="性别" />
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: []
};
},
mounted() {
this.getData();
},
methods: {
/** 模拟从接口获取动态数据 */
getData() {
setTimeout(() => {
const data = [
{
name: '龙一',
age: 21,
sex: '男'
},
{
name: '王二',
age: 22,
sex: '女'
},
{
name: '张三',
age: 21,
sex: '女'
},
{
name: '李四',
age: 21,
sex: '男'
},
{
name: '麻五',
age: 21,
sex: '男'
},
{
name: '老六',
age: 22,
sex: '男'
},
{
name: '小七',
age: 22,
sex: '男'
},
{
name: '阿八',
age: 22,
sex: '女'
},
{
name: '九九',
age: 22,
sex: '男'
}
];
this.tableData = this.handleTableData(data, 'sex');
}, 100);
},
/**
* @desc 处理数据-计算合并的行存储起来
* @param {Array} data 接口返回的数据集合
* @param {String} prop 需要合并的列
* @returns {Array} 处理之后的数据集合
*/
handleTableData(data, prop) {
const tableData = (data || []).map((ele) => {
if (prop) {
// $merge用来记录合并信息
if (!ele.$merge) {
ele.$merge = {};
}
}
return ele;
});
let pos = 0; // 用来记录合并起始行的下表
const len = tableData.length;
for (let i = 0; i < len; i++) {
const item = tableData[i];
if (i === 0) {
item.$merge[prop] = 1;
pos = 0;
}
if (i !== 0) {
// 判断当前行的值与上一行的值是否相等
const flag = item[prop] === tableData[i - 1][prop];
if (flag) {
// 如果当前行的值与上一行的值相等,则当在当前行数据中加入$merge信息记录当前行是需要合并的
item.$merge[prop] = 0;
tableData[pos].$merge[prop] = tableData[pos].$merge[prop] + 1; // 将记录合并起始行的数据中的合并行数+1,后续处理合并时就可以直接知道当前要合并几行数据
} else {
// 如果是不相等,则记录当前行是不合并
item.$merge[prop] = 1;
// 并且将合并起始行位置设置为当前下标
pos = i;
}
}
}
return tableData;
},
/** 处理列合并 */
objectSpanMethod(params) {
const { row, column } = params;
const { property } = column;
if (property === 'sex') {
// 当当前列是需要合并的列时,从之前存储合并信息的$merge找到当前列的合并信息,进行数据合并
return {
rowspan: row.$merge[property], // 设置当前单元格占据几行
colspan: row.$merge[property] ? 1 : 0 // 1 代表显示当前单元格,0代表不显示
};
}
}
}
};
</script>
<style scoped>
.container {
background-color: #fff;
padding: 8px;
}
</style>
<template>
<div class="container">
<el-table
:data="tableData"
:span-method="objectSpanMethod"
border
style="width: 100%"
>
<el-table-column prop="name" label="姓名" />
<el-table-column prop="age" label="年龄" />
<el-table-column prop="sex" label="性别" />
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: []
};
},
mounted() {
this.getData();
},
methods: {
/** 模拟从接口获取动态数据 */
getData() {
setTimeout(() => {
const data = [
{
name: '龙一',
age: 21,
sex: '男'
},
{
name: '王二',
age: 22,
sex: '女'
},
{
name: '张三',
age: 21,
sex: '女'
},
{
name: '李四',
age: 21,
sex: '男'
},
{
name: '麻五',
age: 21,
sex: '男'
},
{
name: '老六',
age: 22,
sex: '男'
},
{
name: '小七',
age: 22,
sex: '男'
},
{
name: '阿八',
age: 22,
sex: '女'
},
{
name: '九九',
age: 22,
sex: '男'
}
];
this.tableData = this.handleTableData(data, 'sex');
}, 100);
},
/**
* @desc 处理数据-计算合并的行存储起来
* @param {Array} data 接口返回的数据集合
* @param {String} prop 需要合并的列
* @returns {Array} 处理之后的数据集合
*/
handleTableData(data, prop) {
const tableData = (data || []).map((ele) => {
if (prop) {
// $merge用来记录合并信息
if (!ele.$merge) {
ele.$merge = {};
}
}
return ele;
});
let pos = 0; // 用来记录合并起始行的下表
const len = tableData.length;
for (let i = 0; i < len; i++) {
const item = tableData[i];
if (i === 0) {
item.$merge[prop] = 1;
pos = 0;
}
if (i !== 0) {
// 判断当前行的值与上一行的值是否相等
const flag = item[prop] === tableData[i - 1][prop];
if (flag) {
// 如果当前行的值与上一行的值相等,则当在当前行数据中加入$merge信息记录当前行是需要合并的
item.$merge[prop] = 0;
tableData[pos].$merge[prop] = tableData[pos].$merge[prop] + 1; // 将记录合并起始行的数据中的合并行数+1,后续处理合并时就可以直接知道当前要合并几行数据
} else {
// 如果是不相等,则记录当前行是不合并
item.$merge[prop] = 1;
// 并且将合并起始行位置设置为当前下标
pos = i;
}
}
}
return tableData;
},
/** 处理列合并 */
objectSpanMethod(params) {
const { row, column } = params;
const { property } = column;
if (property === 'sex') {
// 当当前列是需要合并的列时,从之前存储合并信息的$merge找到当前列的合并信息,进行数据合并
return {
rowspan: row.$merge[property], // 设置当前单元格占据几行
colspan: row.$merge[property] ? 1 : 0 // 1 代表显示当前单元格,0代表不显示
};
}
}
}
};
</script>
<style scoped>
.container {
background-color: #fff;
padding: 8px;
}
</style>
效果图