本文使用的技术栈是vue2+element
1、需求一:将所有内容相同且相邻的行单元格合并
1、需求分析
- 我们判断行的合并首先要从第一列开始判断,
从前往后判断
,其列上相邻的表格内容是否相同 - 如果相同即进行合并,否则(前面列的表格都不相同,也没必要继续往下判断了)都就不会往下判断(即再判断第二列,第三列.....)
思路:首先使用getSpanArray
方法创建spanArr
数组,spanArr
数组是一个二维数组
, 在这里我使用了element里的:span-method="objectSpanMethod"
方法,objectSpanMethod
会根据spanArr
数组进行合并处理
例子如图所示:
组件TableMerge
<template>
<div style="padding-top: 20px">
<el-table
:data="tableData"
:span-method="objectSpanMethod"
style="width: 100%"
>
<el-table-column
v-for="column in columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
props: {
tableData: {
type: Array,
default: () => [],
},
columns: {
type: Array,
default: () => [],
},
},
data() {
return {
spanArr: [],
};
},
mounted() {
this.getSpanArray(this.tableData,this.columns);
},
methods: {
getSpanArray(data, columns) {
// 每次进入方法都先将spanArr数组清空,防止数据多次往数组内推入,导致数据叠加在一起
this.spanArr = []
// 1.首先将每一列的字段名都提取出来(便于接下来进行判断)
const arr = columns.map((e) => e.prop);
// 2.创建数组nameObj,此数组用来保存正在循环的行数
const nameObj = new Array(arr.length).fill(0);
for (let i = 0; i < data.length; i++) {
//3.遍历循环表格数组,判断如果是表格的第一行,那么就进行保底操作根据arr的长度生成对应的个数,并将每个数值做成1(保底操作,因为只要表格有数据,那么第一行肯定至少占单元格1,因此保底)
if (i === 0) {
this.spanArr[0] = new Array(arr.length).fill(1);
// 记录当前循环的行
nameObj[0] = 0;
} else {
//4.创建newRow数组,此数组即每行单元格占的个数,即spanArr二维数组的每一项数组
let newRow = [];
5.创建isEqual变量作为开关
let isEqual = true;
6.遍历上面创建的字段数组arr,因为判断是需要与当前项的上一项判断内容是否相等才会进行合并,所以在上一步加了个开关,默认一直为true的状态,一旦当前项的上一项判断内容不同直接把开关关闭,相当于结束了循环里的操作
for (let j = 0; j < arr.length; j++) {
if (data[i][arr[j]] === data[i - 1][arr[j]] && isEqual) {
this.spanArr[nameObj[j]][j] += 1;
newRow.push(0);
} else {
// 一旦当前项的上一项判断内容不同直接把开关关闭,相当于结束了循环里的操作
isEqual = false;
newRow.push(1);
nameObj[j] = i;
}
}
// 7.最后spanArr数组把处理好的newRow数组存起来即可
this.spanArr.push(newRow);
}
}
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
// 此处是给每一项进行了合并操作
const _row = this.spanArr[rowIndex][columnIndex];
const _col = _row > 0 ? 1 : 0;
return { rowspan: _row, colspan: _col };
},
},
};
</script>
组件接受两个数据,即
tableData表格数据
+columns表格列的循环与其取值
代码的相关解释写在代码块里了
使用组件TableMerge
<template>
<div>
<TableMerge
:tableData="tableData"
:columns="columns"
></TableMerge>
</div>
</template>
<script>
import TableMerge from "@/components/TableMerge.vue";
export default {
name: "ProjectWebHomeView",
components: {
TableMerge,
},
data() {
return {
tableData: [
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
age:'18'
},
{
date: "2016-05-02",
name: "王小虎1",
address: "上海市普陀区金沙江路 1517 弄",
age:'18'
},
{
date: "2016-05-02",
name: "王小虎1",
address: "上海市普陀区金沙江路 1517 弄",
age:'19'
},
{
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀区金沙江路 1516 弄",
age:'18'
},
{
date: "2016-05-03",
name: "王小虎1",
address: "上海市普陀区金沙江路 1512弄",
age:'18'
}, {
date: "2016-05-03",
name: "王小虎1",
address: "上海市普陀区金沙江路 1518弄",
age:'19'
},
],
columns:[
{
prop:'date',
label:'日期',
width:'200'
},
{
prop:'name',
label:'姓名',
width:'140'
},
{
prop:'address',
label:'地址',
width:'240'
},
{
prop:'age',
label:'年龄',
width:'200'
}
]
};
},
mounted() {},
methods: {},
};
</script>
<style lang="scss" scoped></style>
2、需求二:优化==>只针对与指定列进行单元格合并
需求一的操作是针对了所有列表格进行了合并操作,但我们有时候需要只合并某些列,那么我们继续要对代码再次进行优化,效果如下:下图只针对了第一列进行合并
- 下面是完整代码
- 组件多添加了mergeTable参数,来判断表格是否进行表格合并操作
<template>
<div style="padding-top: 20px">
<el-table
:data="tableData"
:span-method="objectSpanMethod"
style="width: 100%"
>
<el-table-column
v-for="column in columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
props: {
tableData: {
type: Array,
default: () => [],
},
columns: {
type: Array,
default: () => [],
},
mergeTable: {
type: Boolean,
default: false,
},
},
data() {
return {
spanArr: [],
};
},
mounted() {
this.getSpanArray(this.tableData, this.columns);
},
methods: {
getSpanArray(data, columns) {
const arr = columns.map((e) => e.prop);
const nameObj = new Array(arr.length).fill(0);
for (let i = 0; i < data.length; i++) {
if (i === 0) {
this.spanArr[0] = new Array(arr.length).fill(1);
nameObj[0] = 0;
} else {
let newRow = [];
let isEqual = true;
for (let j = 0; j < arr.length; j++) {
if (columns[j].isMerge === false) {
isEqual = false;
newRow.push(1);
nameObj[j] = i;
}
if (data[i][arr[j]] === data[i - 1][arr[j]] && isEqual) {
this.spanArr[nameObj[j]][j] += 1;
newRow.push(0);
} else {
isEqual = false;
newRow.push(1);
nameObj[j] = i;
}
}
this.spanArr.push(newRow);
}
}
},
objectSpanMethod({rowIndex, columnIndex }) {
if (this.mergeTable) {
const _row = this.spanArr[rowIndex][columnIndex];
const _col = _row > 0 ? 1 : 0;
return { rowspan: _row, colspan: _col };
} else {
return { rowspan: 1, colspan: 1 };
}
},
},
};
</script>
- 组件使用
- 再想组件传递需要传递mergeTable为true才会进行合并表格操作
- 传递的columns数组对象的每项对象,需要新添加一个isMerge的属性,true则是对此列进行合并表格的操作,false则不进行合并
<template>
<div>
<TableMerge
:tableData="tableData"
:columns="columns"
:mergeTable="true"
></TableMerge>
</div>
</template>
<script>
import TableMerge from "@/components/tableCellTip.vue";
export default {
name: "ProjectWebHomeView",
components: {
TableMerge,
},
data() {
return {
tableData: [
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
age:'18'
},
{
date: "2016-05-02",
name: "王小虎1",
address: "上海市普陀区金沙江路 1517 弄",
age:'18'
},
{
date: "2016-05-02",
name: "王小虎1",
address: "上海市普陀区金沙江路 1517 弄",
age:'19'
},
{
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀区金沙江路 1516 弄",
age:'18'
},
{
date: "2016-05-03",
name: "王小虎1",
address: "上海市普陀区金沙江路 1512弄",
age:'18'
}, {
date: "2016-05-03",
name: "王小虎1",
address: "上海市普陀区金沙江路 1518弄",
age:'19'
},
],
columns:[
{
prop:'date',
label:'日期',
width:'200',
isMerge:true
},
{
prop:'name',
label:'姓名',
width:'140',
isMerge:false
},
{
prop:'address',
label:'地址',
width:'240',
isMerge:false
},
{
prop:'age',
label:'年龄',
width:'200',
isMerge:false
}
]
};
},
mounted() {},
methods: {},
};
</script>
<style lang="scss" scoped></style>
完结👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌