在‘将excel表格转换为element table(上)’我们把excel 转换后通过数据重构绑定到了element table上,现在要做的就是根据源文件进行行列进行合并操作
先看看最终处理的结果
这里在一步步分析实现步骤。
先分析一下合并的逻辑
大致思路理理如上。
思路有了接下来就是一步步的去实现了
- 第一步
首先通过分组的数据找到哪些行有合并操作
this.existMergeRow = {};
this.existMergeCol = {};
this.mergeColAtRow = {};
const existMergeRow = this.existMergeRow// 合并行行为记录
const existMergeCol = this.existMergeCol // 合并列行为记录
const mergeColAtRow = this.mergeColAtRow;// 记录合并列是属于哪一行的
// 计算出哪些行有合并参与合并行为,因为有的行完全没有合并操作,在table merge操作是需要特殊处理renter {rowspan:1,colspan:1}
Object.keys(categoryCN).map(key => {
categoryCN[key].forEach((e) => {
// 有e.rowspan才执行如下操作
if (e.rowspan) {
if (!existMergeRow[key]) { existMergeRow[key] = {} }
let rowspanNum = parseInt(e.rowspan);
const rowNum = e.rowNum - 4;// 行数
existMergeRow[key][rowNum] = true;// 标识他合并了
let step = 1;
while (rowspanNum > 1) {
existMergeRow[key][rowNum + step] = true;// 标识他合并了
step++;
rowspanNum -= 1;
}
}
})
- 第二步
根据分组数据找到哪些列有合并操作,我们直接找上面的方法中添加如下代码来记录有合并操作的列
if (e.colspan) {
const keynum = parseInt(key) - 1
const rowNumm = e.rowNum - 4;
const colNum = e.colNum;// 列数
// 行号:列号
if (!mergeColAtRow[rowNumm]) { mergeColAtRow[rowNumm] = {} }
mergeColAtRow[rowNumm][colNum] = true;
if (!existMergeCol[keynum]) { existMergeCol[keynum] = {} }
let colspanNum = parseInt(e.colspan);
existMergeCol[keynum][colNum] = true;// 标识他合并了
let colstep = 1;
while (colspanNum > 1) {
existMergeCol[keynum][colNum + colstep] = true;// 标识他合并了
mergeColAtRow[rowNumm][colNum + colstep] = true;
colstep++;
colspanNum -= 1;
}
}
- 第三步
拷贝objectSpanMethod 来进行合并操作,大致如下
objectSpanMethod ({ rowIndex, columnIndex }) {
// 需要合并的列
const mergeRow = this.categoryCN[columnIndex];
// 合并列先找到那一例属于哪一行
const mergeColAtRow = this.mergeColAtRow[rowIndex];
// 通过列index 获取这一列,哪些行有合并行为
const existMergeRow = this.existMergeRow[columnIndex]
const existMergeCol = this.existMergeCol[columnIndex]
if (mergeRow) {
let rowspanObj = mergeRow.find((ee, index) => (ee.rowNum - 4) == rowIndex)
// 第一列
if (columnIndex == 0) {
// 判断改行是否参与合并行为
if (existMergeRow[rowIndex]) {
if (rowspanObj) {
const _row = rowspanObj.rowspan
const _col = rowspanObj.colspan
return {
rowspan: _row ? _row : _col ? 1 : 0,
colspan: _col ? _col : _row ? 1 : 0
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
} else { // 其它列,合并操作
// 有行合并也有列合并
if (existMergeRow && existMergeRow[rowIndex] && existMergeCol && existMergeCol[columnIndex]) {
if (rowspanObj) {
const _row = rowspanObj.rowspan
const _col = rowspanObj.colspan
return {
rowspan: _row ? _row : _col ? 1 : 0,
colspan: _col ? _col : _row ? 1 : 0
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
} else if (existMergeRow && existMergeRow[rowIndex]) {// 只有行合并行为
if (rowspanObj) {
const _row = rowspanObj.rowspan
const _col = rowspanObj.colspan
return {
rowspan: _row ? _row : _col ? 1 : 0,
colspan: _col ? _col : _row ? 1 : 0
}
} else {
// 除开第一列,其它行进行合并后,未合并的行需要隐藏,避免出现多行错乱问题
return {
rowspan: 0,
colspan: 0
}
}
}
}
}
// 找合并列对应的那一行,避免所有列做重复操作
if (mergeColAtRow && mergeColAtRow[columnIndex]) {
const mergeRowPlus = this.categoryCN[columnIndex];
if (mergeRowPlus) {
// 只有列表合并,
let colspanObj = mergeRowPlus.find((ee, index) => ee.colNum == columnIndex && (ee.rowNum - 4) == rowIndex)
if (colspanObj) {
const _col = colspanObj.colspan
return {
rowspan: 1,
colspan: _col
}
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
},
这个逻辑有的多 , 因为第一列合并操作有点特殊需要单独操作,后面的行合并又是单独的,而列合并又需要单独写逻辑。
哎不管了经过上面一系列的折腾简单的行列合并算是可以实现了,其它的情况后续再研究研究…
- 最后把源码与测试数据保存一份到 github.com/dengxiaoning/excelToTable,如有需要的小伙伴请自取
补充【20240704】:上面完成了行,列简单的合并操作,但是在具有行列同时合并的操作时就会出现问题,于是今个几个晚上的思考找到了解决方案
如图
1、 存在行列同时合并的情况比较特殊,如合并一个两行两列, 那么在合并第一行时就已经完成了行列合并操作,下面的一行在同一个位置就不需要做任何操作
2、 找到存在有行列同时合并的那一行数据,根据columnIndex 再从分组数据组查找是否存在真正合并的操作
如果没有那就代表改行只是参与了合并行为,但他本身不需要进行合并(上一行或列已经完成了合并操作)
核心代码如下
1、收集哪些存在与行列合并相关的所有行数据,在数据组装方法assemblyTableData
中增加如下判断
if (e.rowspan && e.colspan) {
const keynum = parseInt(key) - 1
const rowNumm = e.rowNum - 4;
const colNum = e.colNum;// 列数
// 行号:列号
if (!existRowColMerge[rowNumm]) { existRowColMerge[rowNumm] = {} }
existRowColMerge[rowNumm][colNum] = true;
// 他合并了几行,记录下一次合并
let rowspanNum = parseInt(e.rowspan);
// if (!existMergeCol[keynum]) { existMergeCol[keynum] = {} }
let colspanNum = parseInt(e.colspan);
// existMergeCol[keynum][colNum] = true;// 标识他合并了
let colstep = 1;
while (colspanNum > 1) {
// existMergeCol[keynum][colNum + colstep] = true;// 标识他合并了
existRowColMerge[rowNumm][colNum + colstep] = true;
colstep++;
colspanNum -= 1;
}
// 存在行列同时合并的情况比较特殊,如合并一个两行两列,
// 那么在合并第一行时就已经完成了行列合并操作,下面的一行在同一个位置就不需要做任何操作
let step = 1;
while (rowspanNum > 1) {
if (!existRowColMerge[rowNumm + step]) { existRowColMerge[rowNumm + step] = {} }
existRowColMerge[rowNumm + step] = existRowColMerge[rowNumm];// 下一行 标识他合并了,可以直接使用上一行的数据
step++;
rowspanNum -= 1;
}
2、在合并方法objectSpanMethod
中增加如下行列合并判断
// 【存在行列同时合并】找到存在有行列同时合并的那一行数据,根据columnIndex 再从分组数据组查找是否存在真正合并的操作
// 如果没有那就代表改行只是参与了合并行为,但他本身不需要进行合并(上一行或列已经完成了合并操作)
if (existRowColMerge && existRowColMerge[columnIndex]) {
const mergeRowPlus = this.categoryCN[columnIndex];
if (mergeRowPlus) {
// 存在行列同时合并,
let colspanObj = mergeRowPlus.find((ee, index) => ee.colNum == columnIndex && (ee.rowNum - 4) == rowIndex)
if (colspanObj) {
const _col = colspanObj.colspan
const _row = colspanObj.rowspan
return {
rowspan: _row,
colspan: _col
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
最后的合并效果