在‘将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) - 1const 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.rowspanconst _col = rowspanObj.colspanreturn {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.rowspanconst _col = rowspanObj.colspanreturn {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.rowspanconst _col = rowspanObj.colspanreturn {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.colspanreturn {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) - 1const 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.colspanconst _row = colspanObj.rowspanreturn {rowspan: _row,colspan: _col}} else {return {rowspan: 0,colspan: 0}}} else {return {rowspan: 0,colspan: 0}}}
最后的合并效果