
Element 单元格合并
vue2、vue3单元格合并
·
前言
最近有个需求,要对相同值的单元格进行合并,踩了一下坑,顺便记录一下,方便以后的使用。
欢迎留言,允许转载,转载麻烦说明来源,创作不易
Vue2 实现
官方api
:span-method="objectSpanMethod"
objectSpanMethod({ row, column, rowIndex, columnIndex })
row
代表行属性,column
代表列属性,rowIndex
代表行下标,columnIndex
代表列下标
初始数据
<template>
<div>
<el-table :data="tableData" border style="width: 60%">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="amount1" label="数值1" />
<el-table-column prop="amount2" label="数值2" />
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData:[
{name:'Tom',amount1:10,amount2:15},
{name:'Tom',amount1:11,amount2:16},
{name:'Jack',amount1:12,amount2:17},
{name:'Andy',amount1:13,amount2:18},
{name:'Andy',amount1:14,amount2:19}
]
};
},
methods: {
}
};
</script>
实例1:合并第一列的前两行
//合并方法
objectSpanMethod({ row, column, rowIndex, columnIndex }){
if(columnIndex==0){
//如果是第一行,就合并两行
if(rowIndex==0){
return {
rowspan:2,
colspan:1
}
}
}
}
可以看出是数据错列了。原因如下:
虽然第0行,让他合并了两行一列,但是第二行的那个tom是还存在的,所以导致错行。
正确的方式应该是第一行合并后,其余多出来的应该隐藏掉。隐藏单元格可以通过{rowspan:0,colspan:0}
来实现,表示不渲染(两个都等于0,或者某一个等于0都行,后面会用到这里)
//合并方法
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
let _row = 2;
if (columnIndex == 0) {
//如果是第一行,就合并两行
if (rowIndex == 0) {
return {
rowspan: _row,
colspan: 1,
};
} else {
//其他行
//因为合并了前两行,第0行已经占两行了,第一行,应该隐藏,其他行正常显示
if (rowIndex < _row) {
return {
rowspan: 0,
colspan: 1,
};
}
}
}
},
实例2:第一列相同姓名的行合并
上面那个例子,实际用处不大,但是可以作为一个很好理解的例子。基于实例1,开始实现实例2 。
数据可以简化成 Tom Tom Jack Andy Andy,按照实例1,合并的行数应该是2,0,1,2,0(2表示合并两行,0表示要隐藏,依次类推),得到这几个数字就是我们需要处理的逻辑,具体逻辑如下:
//获取要合并的行数
getSpanNumber(data, prop) {
//data要处理的数组,prop要合并的属性,比如name
//数组的长度,有时候后台可能返回个null而不是[]
let length = Array.isArray(data) ? data.length : 0;
if (length > 0) {
//用于标识位置
let position = 0;
//用于对比的数据
let temp = data[0][prop];
//要返回的结果
let result = [1];
//假设数据是AABCC,我们的目标就是返回20120
for (let i = 1; i < length; i++) {
if (data[i][prop] == temp) {
//标识位置的数据加一
result[position] += 1;
//当前位置添0
result[i] = 0;
} else {
//不相同时,修改标识位置,该位置设为1,修改对比值
position = i;
result[i] = 1;
temp = data[i][prop];
}
}
//返回结果
return result;
} else {
return [0];
}
},
测试一下数据:
mounted() {
console.log("结果:", this.getSpanNumber(this.tableData,'name'));
},
实现上面的需求
<template>
<div>
<el-table :data="tableData" border style="width: 60%" :span-method="objectSpanMethod">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="amount1" label="数值1" />
<el-table-column prop="amount2" label="数值2" />
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{ name: "Tom", amount1: 10, amount2: 15 },
{ name: "Tom", amount1: 11, amount2: 16 },
{ name: "Jack", amount1: 12, amount2: 17 },
{ name: "Andy", amount1: 13, amount2: 18 },
{ name: "Andy", amount1: 14, amount2: 19 },
],
};
},
mounted() {
console.log("结果:", this.getSpanNumber(this.tableData, "name"));
},
methods: {
//合并方法
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex == 0) {
//合并相同的名字
let nameSpan = this.getSpanNumber(this.tableData, "name");
return {
rowspan: nameSpan[rowIndex],
colspan: 1,
};
}
},
//获取要合并的行数
getSpanNumber(data, prop) {
//data要处理的数组,prop要合并的属性,比如name
//数组的长度,有时候后台可能返回个null而不是[]
let length = Array.isArray(data) ? data.length : 0;
if (length > 0) {
//用于标识位置
let position = 0;
//用于对比的数据
let temp = data[0][prop];
//要返回的结果
let result = [1];
//假设数据是AABCC,我们的目标就是返回20120
for (let i = 1; i < length; i++) {
if (data[i][prop] == temp) {
//标识位置的数据加一
result[position] += 1;
//当前位置添0
result[i] = 0;
} else {
//不相同时,修改标识位置,该位置设为1,修改对比值
position = i;
result[i] = 1;
temp = data[i][prop];
}
}
//返回结果
return result;
} else {
return [0];
}
},
},
};
</script>
结果:
vue3 实现
<template>
<el-table
:data="tableData"
style="width: 100%"
border
:span-method="objectSpanMethod"
>
<el-table-column prop="date" label="Date" width="180" />
<el-table-column prop="name" label="Name" width="180" />
<el-table-column prop="address" label="Address" />
</el-table>
</template>
<script lang="ts" setup>
import { reactive } from "vue";
const states = reactive({
mergeArr: ["name", "address"],
mergeObj: {},
});
const tableData = [
{
date: "2016-05-03",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-02",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-04",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-01",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
];
// 默认接受四个值 { 当前行的值, 当前列的值, 行的下标, 列的下标 }
const objectSpanMethod = ({ column, rowIndex }) => {
// 判断列的属性
if (states.mergeArr.indexOf(column.property) !== -1) {
// 判断其值是不是为0
if (states.mergeObj[column.property][rowIndex]) {
return [states.mergeObj[column.property][rowIndex], 1];
} else {
// 如果为0则为需要合并的行
return [0, 0];
}
}
};
const getSpanArr = (data) => {
states.mergeArr.forEach((key) => {
let count = 0; // 用来记录需要合并行的起始位置
states.mergeObj[key] = []; // 记录每一列的合并信息
data.forEach((item, index) => {
if (index === 0) {
states.mergeObj[key].push(1);
} else {
// 判断当前行是否与上一行其值相等 如果相等 在 count 记录的位置其值 +1 表示当前行需要合并 并push 一个 0 作为占位
if (item["id"] === data[index - 1]["id"]) {
states.mergeObj[key][count] += 1;
states.mergeObj[key].push(0);
} else {
// 如果当前行和上一行其值不相等
count = index; // 记录当前位置
states.mergeObj[key].push(1); // 重新push 一个 1
}
}
});
});
};
getSpanArr(tableData);
</script>
更多推荐
所有评论(0)