超详细多表头位置计算实现

在处理网页中的表格导出Excel时,表格的多表头需要具体的位置。而网页中的多表头,都是采用 colspan 和 rowspan 表示。headRows 采用二维数组表示多表头。

思路

  • 根据属性 colspan 得到单元格相对于当前行的相对位置 X ,后一行的位置等于 prevRow.X +prevRow.colspan
  • 根据属性 rowspan 计算跨行导致,纠正某些单元格被覆盖的情况,既 X 相等的单元格 ,需要向后移动当前单元格的 colspan 个单位。

原始表格

A(0,0)B(3,0)C(4,0)D(6,0)
EFG
HIJKL
###根据`colspan`计算相对位置 `x` `Y` 根据原始表格可知,当前**3X7**的表格,X 坐标的取值范围【0~6】,Y 的取值范围【0~2】,经过第一次计算,得到如下表格
(0,0)A(1,0)(2,0)(3,0)B(4,0)C(5,0)(6,0)D
(0,1)E(1,1)(2,1)F(3,1)G(4,1)(5,1)(6,1)
(0,2)H(1,2)I(2,2)J(3,2)K(4,2)L(5,2)(6,2)
同原始表格个对比,得到如下结果 - 第二行,G 列位置本来应该是(5,1),结果经过第一计算,它跑到了(3,1)这个位置 - 第三行,J K L 三列的位置都分别提前了2个单位。

造成位置提前的原因,主要就是rowspan,跨列导致。

  • 第二行 G 的位置提前,受第一行 B C存在行合并
  • 第三行 J K L 位置提前,受到 第一行 B 第二行 F 存在行合并

由此可知行合并影响的的行,受 rowspan 的跨度确定,即需要移动的单元个需满足两个条件

  1. 移动单元格 存在 rowspan 单元格的后边 cur.pos.x>=nextcur.pos.x
  2. 移动单元格 两个单元格的Y之差,小于合并行的跨度, nextcur.pos.y-cur.pos.y<cur.rowspan

根据rowspan计算正确的 X

知道计算逻辑后,还有一个需要注意的地方,行遍历需要从最后一行开始遍历。因为在第一行 B 这一列这种情况。

  • B 在第一次计算后,在当前行的位置X=3
  • 与之后边的行中X=3的列分别是第二列的 G 和第三列的 K,而我们想要与之对应的 J

这主要是因为,在第二行的F 列存在行合并,导致 J 的位置提前了。所以,如果从正向开始遍历,J这列的位置 X 始终少了一个单位。

 // author:Herbert 
 // QQ:464884492
 function (headRows) {
            var findFieldRows = void 0;
            //计算同一行x的位置
            headRows.forEach(function (rowCols, y) {
                var nextPosx = 0;
                rowCols.forEach(function (col, x) {
                    col.pos = {};
                    col.pos.x = nextPosx;
                    col.pos.y = y;
                    col.colspan = col.colspan || 1;
                    nextPosx = nextPosx + col.colspan;
                });
            });
            //计算 rowspan对后边行的影响
            for (var rowIndex = headRows.length - 1; rowIndex >= 0; rowIndex--) {
                var curRow = headRows[rowIndex];
                for (var cellIndex = 0; cellIndex < curRow.length; cellIndex++) {
                    var curCell = curRow[cellIndex];
                    console.log("正在处理的行:=》", curCell);
                    curCell.rowspan = curCell.rowspan || 1;
                    if (curCell.rowspan > 1) {
                        //将后边行中所有与当前cell相同位置的单元格依次后移当前单元格x相等的单元格后移当前单元格clospan个单位
                        //当前行影响以后(被rowspan包含)所有的行
                        for (var nextRowindex = rowIndex + 1; nextRowindex < headRows.length && curCell.rowspan > nextRowindex - rowIndex; nextRowindex++) {
                            //判断是否存在合并信息
                            var nextRow = headRows[nextRowindex];
                            for (var nextCellIndex = 0; nextCellIndex < nextRow.length; nextCellIndex++) {
                                var nextCell = nextRow[nextCellIndex];
                                if (nextCell.pos.x >= curCell.pos.x) {
                                    nextCell.pos.x += curCell.colspan;
                                    console.log("需要移动的列:=》", nextCell);
                                }
                            }
                        }
                    }
                }
        }
    }

测试结果:

  1. rowspan 移动过程
    正在处理的行:=》 { title: 'H', pos: { x: 0, y: 2 }, colspan: 1 }
    正在处理的行:=》 { title: 'I', pos: { x: 1, y: 2 }, colspan: 1 }
    正在处理的行:=》 { title: 'J', pos: { x: 2, y: 2 }, colspan: 1 }
    正在处理的行:=》 { title: 'K', pos: { x: 3, y: 2 }, colspan: 1 }
    正在处理的行:=》 { title: 'L', pos: { x: 4, y: 2 }, colspan: 1 }
    正在处理的行:=》 { title: 'E', colspan: 2, pos: { x: 0, y: 1 } }
    正在处理的行:=》 { title: 'F', rowspan: 2, pos: { x: 2, y: 1 }, colspan: 1 }
    需要移动的列:=》 { title: 'J', pos: { x: 3, y: 2 }, colspan: 1, rowspan: 1 }
    需要移动的列:=》 { title: 'K', pos: { x: 4, y: 2 }, colspan: 1, rowspan: 1 }
    需要移动的列:=》 { title: 'L', pos: { x: 5, y: 2 }, colspan: 1, rowspan: 1 }
    正在处理的行:=》 { title: 'G', pos: { x: 3, y: 1 }, colspan: 1 }
    正在处理的行:=》 { title: 'A', colspan: 3, pos: { x: 0, y: 0 } }
    正在处理的行:=》 { title: 'B', rowspan: 3, pos: { x: 3, y: 0 }, colspan: 1 }
    需要移动的列:=》 { title: 'G', pos: { x: 4, y: 1 }, colspan: 1, rowspan: 1 }
    需要移动的列:=》 { title: 'J', pos: { x: 4, y: 2 }, colspan: 1, rowspan: 1 }
    需要移动的列:=》 { title: 'K', pos: { x: 5, y: 2 }, colspan: 1, rowspan: 1 }
    需要移动的列:=》 { title: 'L', pos: { x: 6, y: 2 }, colspan: 1, rowspan: 1 }
    正在处理的行:=》 { title: 'C', rowspan: 2, colspan: 2, pos: { x: 4, y: 0 } }
    需要移动的列:=》 { title: 'G', pos: { x: 6, y: 1 }, colspan: 1, rowspan: 1 }
    正在处理的行:=》 { title: 'D', pos: { x: 6, y: 0 }, colspan: 1 }
  2. 移动完成后效果
    当前列: {"title":"A","colspan":3,"pos":{"x":0,"y":0},"rowspan":1}
    当前列: {"title":"B","rowspan":3,"pos":{"x":3,"y":0},"colspan":1}
    当前列: {"title":"C","rowspan":2,"colspan":2,"pos":{"x":4,"y":0}}
    当前列: {"title":"D","pos":{"x":6,"y":0},"colspan":1,"rowspan":1}
    当前列: {"title":"E","colspan":2,"pos":{"x":0,"y":1},"rowspan":1}
    当前列: {"title":"F","rowspan":2,"pos":{"x":2,"y":1},"colspan":1}
    当前列: {"title":"G","pos":{"x":6,"y":1},"colspan":1,"rowspan":1}
    当前列: {"title":"H","pos":{"x":0,"y":2},"colspan":1,"rowspan":1}
    当前列: {"title":"I","pos":{"x":1,"y":2},"colspan":1,"rowspan":1}
    当前列: {"title":"J","pos":{"x":4,"y":2},"colspan":1,"rowspan":1}
    当前列: {"title":"K","pos":{"x":5,"y":2},"colspan":1,"rowspan":1}
    当前列: {"title":"L","pos":{"x":6,"y":2},"colspan":1,"rowspan":1}
原文地址:https://www.cnblogs.com/yfrs/p/mulittable.html