期望通过每一次分享,让技术的门槛变低,落地更容易。 —— around

目录

  • 1.行&列融合
  • 2.小计行
  • 3.自定义控件
  • 4.样式自定义

前言

旨在解决项目过程中遇到基于el-table实现项目需要的在线类似Excel的编辑统计展示能力,如何应对行列融合、样式修正、小计行添加等需求如何处理。项目web端使用的是vue3+element plus,下面代码介绍等相关内容均以vue3+ts语法描述。

正文

样例代码过长,本文先贴实际效果,如果有符合你的需求,再考虑是否使用。

element 在main中写法_表格列融合


element 在main中写法_elementplus_02

1.行&列融合

我们先关注一下element plus官方的Table文档,下面已经提供了行列融合的属性方法

element 在main中写法_element 在main中写法_03


参考上述内容,我们直接在自己的el-table上添加属性

<el-table :data="tableData" height="calc(100vh - 270px)" :span-method="objectSpanMethod">

完成属性添加之后,紧接着需要实现objectSpanMethod该方法,根据对应传参我将方法实现成如下格式,相关说明我直接以注释的方式写在代码块上

  • 本方法会在加载数据的依照数据行、数据列的维度执行N次,确保每一行每一列属性都会被执行到。row=表示该行属性、rowIndex=行下标、columnIndex=列下标
  • 对于行融合或列融合需要搞清楚你的需求来决定使用哪个属性,单元格纵向融合=columnIndex、单元格横向融合=rowIndex
  • 请结合正文下面的图来看,列columnIndex的下标从0开始,0=部门、1=总计划、2=组别,作者在下面的判断就是根据columnIndex分别为0、1、2情况下如何处理融合的
  • 至于每个单元格该怎么融合,需要考虑的问题是:我该向下融合几个或者是向右融合几个?这个得需要自己去算的,如果不融合,请一定返回{rowspan: 0, colspan: 0,},如果需要融合,纵向请改变rowspan,横向请改变colspan

各位可能有个疑问,每一列向下融合的情况都不同,我该怎么确定融合几个?
答:自己在获取到整个tableRows集合时就直接遍历数据,针对每个需要融合的列或者行,去额外补充到row对象属性里,这样才能向下面代码中,我针对部门与总计划列额外使用了deptCount记录向下有多少数据是一样的,针对组别也额外使用了groupCount记录向下有多少数据是一样的。

//本方法中最重要的是row、rowIndex、columnIndex三个属性,其他的都还好
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
	// 部门、计划合并
	if (columnIndex === 0 || columnIndex === 1) {
		if (row.deptCount > 0) {
			return {
				rowspan: row.deptCount,
				colspan: 1,
			};
		} else {
			return {
				rowspan: 0,
				colspan: 0,
			};
		}
	}
	// 组别合并
	if (columnIndex === 2) {
		if (row.groupCount > 0) {
			return {
				rowspan: row.groupCount,
				colspan: 1,
			};
		} else {
			return {
				rowspan: 0,
				colspan: 0,
			};
		}
	}
};

看不懂没关系,大家可以先看看我准备的默认数据,避免误导大家,我只放2个属性,按顺序对应部门、组别

//原始数据
[
{"superWorkOrganName":"交付部","workOrganName":'一组'},
{"superWorkOrganName":"交付部","workOrganName":'一组'},
{"superWorkOrganName":"交付部","workOrganName":'二组'},
{"superWorkOrganName":"交付部","workOrganName":'三组'},
{"superWorkOrganName":"交付部","workOrganName":'四组'},
{"superWorkOrganName":"外包部","workOrganName":'一组'},
{"superWorkOrganName":"外包部","workOrganName":'二组'},
{"superWorkOrganName":"外包部","workOrganName":'二组'},
]
//融合实际上就像在excel自己框选了指定单元格融合一样,我们也得告诉el-table融合哪些
//加工后变成如下
//规则就是你向下有多少个需要合并,deptCount控制superWorkOrganName,groupCount控制workOrganName
[
{"superWorkOrganName":"交付部","workOrganName":'一组',"deptCount":5,"groupCount":2},
{"superWorkOrganName":"交付部","workOrganName":'一组',"deptCount":0,"groupCount":0},
{"superWorkOrganName":"交付部","workOrganName":'三组',"deptCount":0,"groupCount":3},
{"superWorkOrganName":"交付部","workOrganName":'三组',"deptCount":0,"groupCount":0},
{"superWorkOrganName":"交付部","workOrganName":'三组',"deptCount":0,"groupCount":0},
{"superWorkOrganName":"外包部","workOrganName":'一组',"deptCount":3,"groupCount":1},
{"superWorkOrganName":"外包部","workOrganName":'二组',"deptCount":0,"groupCount":2},
{"superWorkOrganName":"外包部","workOrganName":'二组',"deptCount":0,"groupCount":0},
]

1. 为什么第一列交付部出现了5次,deptCount=5只在第一行出现,后面4行都是0?
答:因为你的合并行只能写在规则的第一行,后面被融合的全部只能写0,否则会导致融合错乱。

2. 每次el-table查询结果集后就需要添加属性来处理融合行列的规则属性吗?
答:是的,如果前台同事逻辑控制不太好,建议直接给后台同事去写,让他每次查询出来后直接融合好,规则说给他听就好。

如果你设置完融合后显示表格直接都错位下去了,别灰心,已经离成功就一步了,看下面的注意事项即可。

最后说明一下最关键部分,单元格融合不管是横向还是纵向,请务必记得只能在首个单元格上设置向下向右合并单元格数量,不能每个单元格都设置,被融合的单元格一定{rowspan: 0, colspan: 0,}

2.小计行

受限el-table中涉及到的行对象格式统一, 所以不可避免的是额外添加的小计行也一定是遵循统一对象属性格式来进行的,这也很可能导致如下面所示情况,周期列(whichWeek)本身显示的是每周时间,但我们得把小计名称放到这个列上来,所以都是自由的,随便写,只要展示到你想要的行去就行。

element 在main中写法_elementplus_04

我怎么保证把小计行放到指定的行?
答:需要在获取后台数据成功后,循环遍历所有行,根据你的规则,例如我的规则是根据组别属性,将组别名称一致的存放到一起,在这个组别名称相同的数据遍历时,记录他们分别需要统计的属性累加,最后在下一次进入,组别名称不等于上一次则新增小计行对象,然后再重新为新的组别名统计。

谁来做这个数据小计的工作?
答:如果前台不涉及如我的效果上有在线编辑修正的功能,则只需要后台来封装即可。如果需要前台编辑再统计,则最好前台封装,封装的时候可以直接将额外自己前台需要的东西一并完成封装,有利于规则的编写。

3.自定义控件

自定义控件实际上就是在el-table上自定义每个单元格的内容,本身并不难,效果如下

element 在main中写法_表格列融合_05


具体编写的格式如下

//以下代码以`人力`列来做说明,
//有一些v-if代码是我用于小计样式还有权限控制用户是否可以编辑处理的,一般不需要
<el-table-column align="center" prop="humanCount" label="人力">
  <template #default="scope">
    <el-input v-if="scope.row.groupPlanEditable && scope.row.whichWeek != 5" class="w100" v-model="scope.row.humanCount" :min="0" :step="1" :controls="false" size="default"
      @input="onHumanCountChange($event, scope.row)" />
    <sapn v-else>{{scope.row.humanCount}}</sapn>
  </template>
</el-table-column>

注意事项主要提供给有需求在前台进行编辑且联动其他编辑框的小伙伴们,例如作者的单元格规则是:入职 * 离职率 = 离职入职 - 离职 = 在职在职 / 人力 = 人效。建议写一个通用的方法,当发生任意可编辑数据变更后,直接对全部的属性重新计算一次,避免分别写不同的规则方法,最后因为数据联动问题导致循环。

4.样式自定义

对于作者前文截图的表格,应该可以发现,单元格margin、padding都是很窄的,如果不自行调整,会导致你单元格显示特别松散,无法在一个屏幕里显示这么多信息,所以需要特定调整一下对于列的样式。
下面的内容均以scss语法说明

  • el-table单元格边距收缩
:deep(.el-table__row) {
	.el-table__cell {
		padding: 2px 0 !important;
		.cell {
			padding: 0 4px !important;
		}
	}
}
  • 输入框内间距
:deep(.el-input-number.is-without-controls .el-input__wrapper) {
	padding-left: 0px !important;
	padding-right: 0px !important;
}
  • 输入框文本居中
:deep(.el-input__wrapper) {
	.el-input__inner {
		text-align: center !important;
	}
}
  • 细节修正
:deep(.el-input--large.el-input__wrapper) {
	padding: 1px 2px !important;
}

:deep(.el-input-group__append, .el-input-group__prepend) {
	padding: 0 10px !important;
}

最后

本文涉及的业务需求功能是部门前端同事做不出来,最后给我做的,从需求到上线花了2天,中间了解el-table相关方法逻辑上花了些时间,特写本文记录对el-table自定义化的改造,便于后续查阅。
若有其他情况解决不了,也可留言咨询