开场诗
-
清川带长薄,车马去闲闲。
-
流水如有意,暮禽相与还。
-
荒城临古渡,落日满秋山。
-
迢递嵩高下,归来且闭关。
一、序言
大家好,这里是流光的频道,先做一下自我介绍,2000年的天蝎座一枚,作为今年刚入职的职场小白经过这几个月的适应逐渐对工作熟悉起来,开始有时间在业余时候记录一下自己在工作中遇到的问题和解决的方法,总结一下自己的收获在下一次再面临相同业务的时候能更加的得心应手。
二、遇到的问题
最近公司有一个新项目需要给一个集团公司做一个软件系统,该公司是一个以制造业为主的公司所以他们就会涉及到许多的报表(类似于excel),但是每张表的格式都不一样。
有这样的:
还有这样的:
甚至还有这样的:
当时我接到任务的时候是一个头两个大我之前并没有做过这样的报表但是也没什么办法既然任务已经来了只能埋头苦干,我们部门的前端用的是React,框架是公司研发的类似于Ant,所以我第一想法是Table组件能否满足我的需求。通过我对Table组件的研究我发现它的几个属性可以达到我想要的效果。

三、解决方法
Table的三个属性
rowSpan:单元格纵向所占格数
colSpan:单元格横向所占格数
render:定制化表格的展示内容
正常情况下:
当我把代码变成这样:
它的展示效果就变成了
能很明显看到当我的表头需要占用的多个单元格的时候可以对他的rowSpan和colSpan属性上进行修改需要被合并的单元格设置为0。就可以实现类似的效果,对于表格的内容也是一样的.
然后根据具体的业务需求对需要进行合并的单元格的数据进行判断,以达到报表的效果,还可以使用useState记录每段数据的长度来动态计算每个单元格所占的格数。在此展示一个最简单的效果:
做到最基础的效果后我想如果每张报表都用这样的方法那岂不是太复杂了所以我经过多方面查证最后把他写成了方法只需要对最后的数据惊醒一下便利就可以轻松展示。
具体的方法如下:
js
//单元格纵向合并
function mergeCell(arr, key) {
var cell = arr.reduce(function(pre, cur) {
if (!pre.includes(cur[key])) {
pre.push(cur[key]);
}
return pre;
}, []);
return cell.map(function(_c) {
var _filter = arr.filter(function(i) {
return i[key] === _c;
});
console.log(_filter);
return _filter.map(function (item, idx) {
let length =0
if (idx === 0 || (idx > 0 && item[key] != _filter[idx - 1][key])) {
// 获取这一类对象的长度,并保存在 length 中
length = _filter.filter(obj => obj[key] === item[key]).length;
Object.defineProperty(item, `${key}-rowSpan`, {
value: length,
enumerable: true, // 可枚举
configurable: true, // 可配置
writable: true // 可写
});
} else {
Object.defineProperty(item, `${key}-rowSpan`, {
value: 0,
enumerable: true, // 可枚举
configurable: true, // 可配置
writable: true // 可写
})
}
});
});
}
//单元格横向向合并
function mergeCell2(arr, value) {
const data = value.map(item => {
return arr
.map(itm => {
if (item.name === itm[item.keyvalue]) {
// 获取这一类对象的长度,并保存在 length 中
return Object.defineProperty(itm, `${item.keyvalue}-colSpan`, {
value: item.length,
enumerable: true, // 可枚举
configurable: true, // 可配置
writable: true // 可写
});
} else {
return itm;
}
})
.map(itm => {
var matchedKeys = null;
if (
item.name === itm[item.keyvalue] &&
item.tiover.every(function(key2) {
matchedKeys = key2;
return Object.prototype.hasOwnProperty.call(itm, key2);
})
) {
console.log(matchedKeys);
return Object.defineProperty(itm, `${matchedKeys}-colSpan`, {
value: 0,
enumerable: true, // 可枚举
configurable: true, // 可配置
writable: true // 可写
});
} else {
return itm;
}
});
});
return data;
}
使用方法
js
const _cell2 = mergeCell(data, 'projrctName');
let data1 = [];
for (let i = 0; i < _cell2.length; i++) {
data1 = [...data1, ..._cell2[i]];
}
const _cell2 = mergeCell2(dataer, [
{ keyvalue: 'project', name: '外购中间品', length: 2, tiover: ['goodname'] }
]);;
let data1 = [];
for (let i = 0; i < _cell2.length; i++) {
data1 = [...data1, ..._cell2[i]];
}
当我想对data中的数据哪一列做表格合并,就使用mergeCell函数第一个参数是传入的数据,第二个参数是我想要合并那一列的列属性就是columns中那一列的dataIndex的值,调用之后它会根据你传入的第二个参数来便利查看数据中有多少不同的值把他们归为不同的数组,在每一个数组的数据中都会生成一个新字段就是:: keyvalue的值-
当你渲染数据的是时候再把他们遍历放到一个大数组中,在生成的时候只需要通过如下方式就可以达到上面图中展示的效果
这是对于单元格纵向合并对于单元格的横向合并可以采用mergeCell2,第一个参数和mergeCell一样,第二个参数是传入一个数组,数组中的对象有4个属性,keyvalue是你要合并的那一列的dataIndex,name是对应那一列你要合并的单元格的名字,length是你要合并多少个单元格,tiover是你合并所占别的列的dataIndex,执行完函数后它会返回一个和列合并相同的数组也多一个字段是: keyvalue的值-colSpan被合并的单元格的这个属性会默认为0,最后展示到Table上就操作成功了。
随想
这只是我在做报表的过程中遇到的一个问题,还有样式怎么修改、怎么优化页面性能、怎么实现用户的实时输入页面的实时更新和计算等问题......有机会的话会在后面的文章中给大家介绍,希望我的方法可以给你带来一点启发,也希望大佬们能指出我还需要改进的地方,好了这篇文章的分享到此结束了,让我们下一篇文章再继续探索。