El-Table 动态合并行/列单元格

excel表格可以方便的合并单元格,el-table也有类似api,有时需求需要根据数据动态合并,这时候就需要我们封装更通用的方法来实现。下面介绍根据单元格值来合并单元格的逻辑。

# ElTable已有Api

强大的elTale已经有合并行列的功能,只需要我们自己处理合并逻辑

提示

通过给table传入span-method方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行row、当前列column、当前行号rowIndex、当前列号columnIndex四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan,第二个元素代表colspan。 也可以返回一个键名为rowspan和colspan的对象。

// row 当前行数据
// column 当前列,包含一些相关属性,label property rowSpan colSpan 等等...
spanMethod({ row, column, rowIndex, columnIndex }) {
  if (rowIndex % 2 === 0) {
    if (columnIndex === 0) {
      return [1, 2];
    } else if (columnIndex === 1) {
      return [0, 0];
    }
  }
}

# 合并行

获取到表格数据,我们先进行遍历,从而计算出需要合并的单元格坐标,即找出相同值的行。封装方法方便通过属性名指定需要合并的行。

export default {
  data(){
    return {
 	  tableData: [
 	    {id: '12987122', name: '王小虎', amount1: '234', amount2: '3.2', amount3: 10},
 		{id: '12987123', name: '王小虎', amount1: '165', amount2: '4.43', amount3: 12},
 		{id: '12987124', name: '张三', amount1: '324', amount2: '1.9', amount3: 12},
 		{id: '12987125', name: '赵四', amount1: '621', amount2: '2.2', amount3: 12},
 		{id: '12987126', name: '赵四', amount1: '539', amount2: '4.1', amount3: 15}
 	  ],
 	  spanMap: {},
 	 };
  },
  mounted(){
    this.initSpanArr(this.tableData, 'name')
 	this.initSpanArr(this.tableData, 'amount3')
  },
  methods: {
    spanMethod( {rowIndex, column: {property}} ){
 	  if(this.spanMap[property]){
 	    const _row = this.spanMap[property].spanArr[rowIndex];
 		const _col = _row > 0 ? 1 : 0;
 		return { // [0,0] 表示这一行不显示, [2,1]表示行的合并数
 		  rowspan: _row,
 		  colspan: _col,
 		};
 	  }
 	},
 	initSpanArr( data, column ){
 	  let contactDot = 0;
 	  this.spanMap[column] = {};
 	  this.spanMap[column].spanArr = [];
 	  data.forEach(( item, index ) => {
 	    if(index === 0){
 		  this.spanMap[column].spanArr.push(1); // 第一行数据 不合并
 		} else {
 		  if(item[column] === data[index - 1][column]){
 		    this.spanMap[column].spanArr[contactDot] += 1; // 下一行,如果数据相同,合并行数加一
 			this.spanMap[column].spanArr.push(0);
 		  } else{
 		    contactDot = index;
 			this.spanMap[column].spanArr.push(1);
 		  }
 		}
 	  });
 	},
  }
 };
<template>
    <el-table :data="tableData" :span-method="spanMethod">
 		<el-table-column prop="id" label="ID" width="180"/>
 		<el-table-column prop="name" label="姓名"/>
 		<el-table-column prop="amount1" label="数值 1"/>
 		<el-table-column prop="amount2" label="数值 2"/>
 		<el-table-column prop="amount3" label="数值 3"/>
 	</el-table>
 </template>
 
 <script>
 export default {
 	data(){
 		return {
 	        tableData: [
 				{id: '12987122', name: '王小虎', amount1: '234', amount2: '3.2', amount3: 10},
 				{id: '12987123', name: '王小虎', amount1: '165', amount2: '4.43', amount3: 12},
 				{id: '12987124', name: '张三', amount1: '324', amount2: '1.9', amount3: 12},
 				{id: '12987125', name: '赵四', amount1: '621', amount2: '2.2', amount3: 12},
 				{id: '12987126', name: '赵四', amount1: '539', amount2: '4.1', amount3: 15}
 			],
 			spanMap: {},
 		};
 	},
 	mounted(){
 		this.initSpanArr(this.tableData, 'name')
 		this.initSpanArr(this.tableData, 'amount3')
 	},
 	methods: {
 		spanMethod( {rowIndex, column: {property}} ){
 			if(this.spanMap[property]){
 				const _row = this.spanMap[property].spanArr[rowIndex];
 				const _col = _row > 0 ? 1 : 0;
 				return { // [0,0] 表示这一行不显示, [2,1]表示行的合并数
 					rowspan: _row,
 					colspan: _col,
 				};
 			}
 		},
 		initSpanArr( data, column ){
 			let contactDot = 0;
 			this.spanMap[column] = {};
 			this.spanMap[column].spanArr = [];
 			data.forEach(( item, index ) => {
 				if(index === 0){
 					this.spanMap[column].spanArr.push(1); // 第一行数据 不合并
 				} else{
 					if(item[column] === data[index - 1][column]){
 						this.spanMap[column].spanArr[contactDot] += 1; // 下一行,如果数据相同,合并行数加一
 						this.spanMap[column].spanArr.push(0);
 					} else{
 						contactDot = index;
 						this.spanMap[column].spanArr.push(1);
 					}
 				}
 			});
 		},
 	}
 };
 </script>
Show Copy

# 合并列

合并列有一些差别

  1. 首先,不能像合并行一样,通过数据处理得到spanArr,因为视图表格中表头顺序未知
  2. 其次,动态合并时,相同列的值会出现多种情况,例如三列数据中三列都相同或者任意两列相同

# 解决方案

我们直接在spanMethod里进行动态处理,动态对比相邻单元格值

首先定义需要合并的列字段,注意需要保证顺序 mergeArr: ['amount1', 'amount2', 'amount3']

spanMethod遍历单元格时,我们依次判断当前单元格之后的值是否相同,以此作为合并格数,同时判断以合并的单元格直接返回[0,0] (不渲染)

spanMethod( {row, column: {property}} ){
  const index = this.mergeArr.findIndex(o => o === property)
    if(index !== -1){
      let colSpan = 1
      // 与前一列相比,相同则不再合并,并取消展示
	  if(row[this.mergeArr[index]] === row[this.mergeArr[index - 1]]){ 
	    return [0, 0] // [0,0] el-table 内部处理为不渲染
	  }
	  for(let i = index; i < this.mergeArr.length; i++){
        // 从当前位置查找相邻相同值
	    if(row[this.mergeArr[index]] === row[this.mergeArr[index + 1]]){ 
		  colSpan++
	    }
	  }
      // [1,5] 从当前位置,合并1行5格
	  return [1, colSpan > 1 ? colSpan - 1 : 1] 
    }
   return [1, 1];
}

下面是具体的完整实现,可打开看详细代码

<template>
	<el-table :data="tableData" :span-method="spanMethod" border>
		<el-table-column prop="id" label="ID" width="180"/>
		<el-table-column prop="name" label="姓名"/>
		<el-table-column prop="amount1" align="center" label="数值 1"/>
		<el-table-column prop="amount2" align="center" label="数值 2"/>
		<el-table-column prop="amount3" align="center" label="数值 3"/>
	</el-table>
</template>

<script>
export default {
	data(){
		return {
			tableData: [
				{id: '12987122', name: '王小虎', amount1: '123', amount2: '123', amount3: '123'},
				{id: '12987123', name: '王小虎', amount1: '165', amount2: '4.43', amount3: 12},
				{id: '12987124', name: '张三', amount1: '324', amount2: 12, amount3: 12},
				{id: '12987125', name: '赵四', amount1: '621', amount2: '2.2', amount3: 12},
				{id: '12987126', name: '赵四', amount1: '539', amount2: '4.1', amount3: 15}
			],
			mergeArr: ['amount1', 'amount2', 'amount3'], // 需要合并的列,注意保证列顺序和表头一致
		};
	},
	methods: {
		spanMethod( {row, column: {property}} ){
			const index = this.mergeArr.findIndex(o => o === property)
			if(index !== -1){
				let colSpan = 1
				if(row[this.mergeArr[index]] === row[this.mergeArr[index - 1]]){ // 与前一列相比,相同则不再合并,并取消展示
					return [0, 0] // [0,0] el-table 内部处理为不渲染
				}
				for(let i = index; i < this.mergeArr.length; i++){
					if(row[this.mergeArr[index]] === row[this.mergeArr[index + 1]]){ // 从当前位置查找相邻相同值
						colSpan++
					}
				}
				return [1, colSpan > 1 ? colSpan - 1 : 1] // [1,5] 从当前位置,合并1行5格
			}
			return [1, 1];
		},
	}
};
</script>
Show Copy
最近更新
01
echarts扇形模拟镜头焦距与可视化角度示意图
03-10
02
vite插件钩子
03-02
03
vite的依赖预构建
02-13
更多文章>