在报表系统中,涉及“HTML的TD单元格的合并”恐怕为数不少。
比如,从DB查得数据并经过后台的整理后,可能是这样的:
Table1
JOB | TOTAL SAL | INDEX | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | ANALYST | 6000 | 1 | 7788 | SCOTT | ANALYST | 7566 | 4/19/1987 | 3000.00 | 20 | |
1 | ANALYST | 6000 | 2 | 7902 | FORD | ANALYST | 7566 | 12/3/1981 | 3000.00 | 20 | |
2 | CLERK | 4150 | 3 | 7934 | MILLER | CLERK | 7782 | 1/23/1982 | 1300.00 | 10 | |
2 | CLERK | 4150 | 4 | 7900 | JAMES | CLERK | 7698 | 12/3/1981 | 950.00 | 30 | |
2 | CLERK | 4150 | 5 | 7369 | SMITH | CLERK | 7902 | 12/17/1980 | 800.00 | 20 | |
2 | CLERK | 4150 | 6 | 7876 | ADAMS | CLERK | 7788 | 5/23/1987 | 1100.00 | 20 | |
3 | MANAGER | 8275 | 7 | 7698 | BLAKE | MANAGER | 7839 | 5/1/1981 | 2850.00 | 30 | |
3 | MANAGER | 8275 | 8 | 7566 | JONES | MANAGER | 7839 | 4/2/1981 | 2975.00 | 20 | |
3 | MANAGER | 8275 | 9 | 7782 | CLARK | MANAGER | 7839 | 6/9/1981 | 2450.00 | 10 | |
4 | PRESIDENT | 5000 | 10 | 7839 | KING | PRESIDENT | 11/17/1981 | 5000.00 | 10 | ||
5 | SALESMAN | 5600 | 11 | 7844 | TURNER | SALESMAN | 7698 | 9/8/1981 | 1500.00 | 0.00 | 30 |
5 | SALESMAN | 5600 | 12 | 7654 | MARTIN | SALESMAN | 7698 | 9/28/1981 | 1250.00 | 1400.00 | 30 |
5 | SALESMAN | 5600 | 13 | 7521 | WARD | SALESMAN | 7698 | 2/22/1981 | 1250.00 | 500.00 | 30 |
5 | SALESMAN | 5600 | 14 | 7499 | ALLEN | SALESMAN | 7698 | 2/20/1981 | 1600.00 | 300.00 | 30 |
为了让用户更清晰地查看报表,结果可能需要是这样的(各职位的薪水总额及分布明细):
Table2
JOB | TOTAL SAL | INDEX | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | ANALYST | 6000 | 1 | 7788 | SCOTT | ANALYST | 7566 | 4/19/1987 | 3000.00 | 20 | |
2 | 7902 | FORD | ANALYST | 7566 | 12/3/1981 | 3000.00 | 20 | ||||
2 | CLERK | 4150 | 3 | 7934 | MILLER | CLERK | 7782 | 1/23/1982 | 1300.00 | 10 | |
4 | 7900 | JAMES | CLERK | 7698 | 12/3/1981 | 950.00 | 30 | ||||
5 | 7369 | SMITH | CLERK | 7902 | 12/17/1980 | 800.00 | 20 | ||||
6 | 7876 | ADAMS | CLERK | 7788 | 5/23/1987 | 1100.00 | 20 | ||||
3 | MANAGER | 8275 | 7 | 7698 | BLAKE | MANAGER | 7839 | 5/1/1981 | 2850.00 | 30 | |
8 | 7566 | JONES | MANAGER | 7839 | 4/2/1981 | 2975.00 | 20 | ||||
9 | 7782 | CLARK | MANAGER | 7839 | 6/9/1981 | 2450.00 | 10 | ||||
4 | PRESIDENT | 5000 | 10 | 7839 | KING | PRESIDENT | 11/17/1981 | 5000.00 | 10 | ||
5 | SALESMAN | 5600 | 11 | 7844 | TURNER | SALESMAN | 7698 | 9/8/1981 | 1500.00 | 0.00 | 30 |
12 | 7654 | MARTIN | SALESMAN | 7698 | 9/28/1981 | 1250.00 | 1400.00 | 30 | |||
13 | 7521 | WARD | SALESMAN | 7698 | 2/22/1981 | 1250.00 | 500.00 | 30 | |||
14 | 7499 | ALLEN | SALESMAN | 7698 | 2/20/1981 | 1600.00 | 300.00 | 30 |
这就需要我们对单元格进行相应的合并。
一般来说,有两种处理方法,
- 在编写HTML时已设置单元格的合并;
- 在编写HTML时未作合并处理,后期由Javascript完成单元格合并工作。
本文讲的是第2种情况。
合并单元格的步骤
比如,我要把上表Table1中数值为ANALYST的两个单元格合并。
JOB |
ANALYST |
ANALYST |
- 我们首先需要将第二个ANALYST的单元格删除掉
- 然后设置第一个ANALYST的单元格的rowSpan属性为2(表示“跨越2行”)
写得不好的公用方法
之前写了一个公用Javascript方法,用以合并相邻间文本相同的单元格。
这个方法写得不好,有明显的Bug。对已做过合并的Table,这个方法有可能导致合并单元格错误。
主要的原因在于,对于合并过单元格的表格,那么被合并的行就会相应的少一个TD,而此方法依旧按未合并过单元格的情况来获取TD对象。
比如,获取第二列的所有单元格,此程序用“获取全部TR中的第二个TD”来实现,这在未合并过单元格的Table是正确的,但对于合并过单元格的Table,则未必,因为被合并的行相应地少一个单元格。
此处将代码贴出,希望大家引以为鉴。
function mergeCell(tableObj, col) { var $tab = $(tableObj); var $trs = $tab.find("tr"); var oldval; var firstTD; var counter = 0; $trs.each(function(index) { if (!oldval && !firstTD) { oldval = $(this).find("td:eq(" + col + ")").text(); firstTD = $(this).find("td:eq(" + col + ")").get(0); counter = 0; counter++; } else { if ($(this).find("td:eq(" + col + ")").text() == oldval) { $(this).find("td:eq(" + col + ")").remove(); counter++; } else { $(firstTD).attr("rowSpan", counter); oldval = $(this).find("td:eq(" + col + ")").text(); firstTD = $(this).find("td:eq(" + col + ")").get(0); counter = 0; counter++; } } if (index >= $trs.length - 1) { $(firstTD).attr("rowSpan", counter); } }); }
mergeCell
页面DEMO如下(HTML代码,较长):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <script type="text/javascript" src="../js/jquery.js"></script> <script type="text/javascript" src="../js/tdmerger.js"></script> <script type="text/javascript"> $().ready(function() { mergeCell($("#list_table").get(0), 1); mergeCell($("#list_table").get(0), 2); }); function mergeCell(tableObj, col) { var $tab = $(tableObj); var $trs = $tab.find("tr"); var oldval; var firstTD; var counter = 0; $trs.each(function(index) { if (!oldval && !firstTD) { oldval = $(this).find("td:eq(" + col + ")").text(); firstTD = $(this).find("td:eq(" + col + ")").get(0); counter = 0; counter++; } else { if ($(this).find("td:eq(" + col + ")").text() == oldval) { $(this).find("td:eq(" + col + ")").remove(); counter++; } else { $(firstTD).attr("rowSpan", counter); oldval = $(this).find("td:eq(" + col + ")").text(); firstTD = $(this).find("td:eq(" + col + ")").get(0); counter = 0; counter++; } } if (index >= $trs.length - 1) { $(firstTD).attr("rowSpan", counter); } }); } </script> <body> <TABLE id="list_table" BORDER="1"> <TR> <TH> </TH> <TH>JOB</TH> <TH>TOTAL SAL</TH> <TH>INDEX</TH> <TH>EMPNO</TH> <TH>ENAME</TH> <TH>JOB</TH> <TH>MGR</TH> <TH>HIREDATE</TH> <TH>SAL</TH> <TH>COMM</TH> <TH>DEPTNO</TH> </TR> <TR> <TD>1</TD> <TD>ANALYST</TD> <TD>6000</TD> <TD>1</TD> <TD>7788</TD> <TD>SCOTT</TD> <TD>ANALYST</TD> <TD>7566</TD> <TD>4/19/1987</TD> <TD>3000.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>1</TD> <TD>ANALYST</TD> <TD>6000</TD> <TD>2</TD> <TD>7902</TD> <TD>FORD</TD> <TD>ANALYST</TD> <TD>7566</TD> <TD>12/3/1981</TD> <TD>3000.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>3</TD> <TD>7934</TD> <TD>MILLER</TD> <TD>CLERK</TD> <TD>7782</TD> <TD>1/23/1982</TD> <TD>1300.00</TD> <TD> </TD> <TD>10</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>4</TD> <TD>7900</TD> <TD>JAMES</TD> <TD>CLERK</TD> <TD>7698</TD> <TD>12/3/1981</TD> <TD>950.00</TD> <TD> </TD> <TD>30</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>5</TD> <TD>7369</TD> <TD>SMITH</TD> <TD>CLERK</TD> <TD>7902</TD> <TD>12/17/1980</TD> <TD>800.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>6</TD> <TD>7876</TD> <TD>ADAMS</TD> <TD>CLERK</TD> <TD>7788</TD> <TD>5/23/1987</TD> <TD>1100.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>3</TD> <TD>MANAGER</TD> <TD>8275</TD> <TD>7</TD> <TD>7698</TD> <TD>BLAKE</TD> <TD>MANAGER</TD> <TD>7839</TD> <TD>5/1/1981</TD> <TD>2850.00</TD> <TD> </TD> <TD>30</TD> </TR> <TR> <TD>3</TD> <TD>MANAGER</TD> <TD>8275</TD> <TD>8</TD> <TD>7566</TD> <TD>JONES</TD> <TD>MANAGER</TD> <TD>7839</TD> <TD>4/2/1981</TD> <TD>2975.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>3</TD> <TD>MANAGER</TD> <TD>8275</TD> <TD>9</TD> <TD>7782</TD> <TD>CLARK</TD> <TD>MANAGER</TD> <TD>7839</TD> <TD>6/9/1981</TD> <TD>2450.00</TD> <TD> </TD> <TD>10</TD> </TR> <TR> <TD>4</TD> <TD>PRESIDENT</TD> <TD>5000</TD> <TD>10</TD> <TD>7839</TD> <TD>KING</TD> <TD>PRESIDENT</TD> <TD> </TD> <TD>11/17/1981</TD> <TD>5000.00</TD> <TD> </TD> <TD>10</TD> </TR> <TR> <TD>4</TD> <TD>SUPER PRESIDENT</TD> <TD>5000</TD> <TD>10</TD> <TD>7839</TD> <TD>KING</TD> <TD>PRESIDENT</TD> <TD> </TD> <TD>11/17/1981</TD> <TD>5000.00</TD> <TD> </TD> <TD>10</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>11</TD> <TD>7844</TD> <TD>TURNER</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>9/8/1981</TD> <TD>1500.00</TD> <TD>0.00</TD> <TD>30</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>12</TD> <TD>7654</TD> <TD>MARTIN</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>9/28/1981</TD> <TD>1250.00</TD> <TD>1400.00</TD> <TD>30</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>13</TD> <TD>7521</TD> <TD>WARD</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>2/22/1981</TD> <TD>1250.00</TD> <TD>500.00</TD> <TD>30</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>14</TD> <TD>7499</TD> <TD>ALLEN</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>2/20/1981</TD> <TD>1600.00</TD> <TD>300.00</TD> <TD>30</TD> </TR> </TABLE> </body> </html>
WrongMergeTD.html
卷土重来
于是,重新写了两个公用方法来合并单元格。
一个是合并相邻值相同的单元格;
另外一个是合并指定序号的单元格,比如2-5,6-8,是“合并第2个至第5个单元格、第6个和至第8个单元格”。
这俩方法将“获取需要合并的TD元素”的动作交由方法调用者,只负责对入参单元格作对应的合并。
JS
/** * Meger cells with same text * @param $tds TDs jquery object * @param type row/col */ function mergeCell4SameText($tds, type) { var oldval; var firstTD; var counter = 0; $tds.each(function(index) { if (index == 0) { oldval = $(this).text(); firstTD = $(this).get(0); counter = 0; counter++; } else { if ($(this).text() == oldval) { $(this).remove(); counter++; } else { if (type == ‘col‘) { $(firstTD).attr("rowSpan", counter); } else if (type == ‘row‘) { $(firstTD).attr("colSpan", counter); } oldval = $(this).text(); firstTD = $(this).get(0); counter = 0; counter++; } } if (index >= $tds.length - 1) { if (type == ‘col‘) { $(firstTD).attr("rowSpan", counter); } else if (type == ‘row‘) { $(firstTD).attr("colSpan", counter); } } }); } /** * Meger cells by the parameters "index" * @param $tds TDs jquery object * @param type row/col * @param index for example, 0-1,2-5,6-8,10-13 */ function mergeCellByIndex($tds, type, index) { var indexArrs = index.split(‘,‘); var fromTo; var from; var to; for (var i in indexArrs) { fromTo = indexArrs[i]; from = new Number(fromTo.split(‘-‘)[0]); to = new Number(fromTo.split(‘-‘)[1]); for (var j = 1 + from; j <= to; j++) { $($tds.get(j)).remove(); } if (type == ‘col‘) { $($tds.get(from)).attr("rowSpan", to - from + 1); } else if (type == ‘row‘) { $($tds.get(from)).attr("colSpan", to - from + 1); } } }
tdmerger
调用的页面(HTML代码,较长):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <script type="text/javascript" src="../js/jquery.js"></script> <script type="text/javascript" src="../js/tdmerger.js"></script> <script type="text/javascript"> $().ready(function() { $col1tds = $("table tr td:nth-child(1)"); $col2tds = $("table tr td:nth-child(2)"); $col3tds = $("table tr td:nth-child(3)"); mergeCellByIndex($col1tds, ‘col‘, ‘0-1,2-5,6-8,10-13‘); mergeCellByIndex($col2tds, ‘col‘, ‘0-1,2-5,6-8,10-13‘); mergeCellByIndex($col3tds, ‘col‘, ‘0-1,2-5,6-8,10-13‘); /* $row2tds = $("table tr:eq(2) td"); mergeCellByIndex($row2tds, ‘row‘, ‘6-11‘); */ }); </script> <body> <TABLE BORDER="1"> <TR> <TH> </TH> <TH>JOB</TH> <TH>TOTAL SAL</TH> <TH>INDEX</TH> <TH>EMPNO</TH> <TH>ENAME</TH> <TH>JOB</TH> <TH>MGR</TH> <TH>HIREDATE</TH> <TH>SAL</TH> <TH>COMM</TH> <TH>DEPTNO</TH> </TR> <TR> <TD>1</TD> <TD>ANALYST</TD> <TD>6000</TD> <TD>1</TD> <TD>7788</TD> <TD>SCOTT</TD> <TD>ANALYST</TD> <TD>7566</TD> <TD>4/19/1987</TD> <TD>3000.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>1</TD> <TD>ANALYST</TD> <TD>6000</TD> <TD>2</TD> <TD>7902</TD> <TD>FORD</TD> <TD>ANALYST</TD> <TD>7566</TD> <TD>12/3/1981</TD> <TD>3000.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>3</TD> <TD>7934</TD> <TD>MILLER</TD> <TD>CLERK</TD> <TD>7782</TD> <TD>1/23/1982</TD> <TD>1300.00</TD> <TD> </TD> <TD>10</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>4</TD> <TD>7900</TD> <TD>JAMES</TD> <TD>CLERK</TD> <TD>7698</TD> <TD>12/3/1981</TD> <TD>950.00</TD> <TD> </TD> <TD>30</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>5</TD> <TD>7369</TD> <TD>SMITH</TD> <TD>CLERK</TD> <TD>7902</TD> <TD>12/17/1980</TD> <TD>800.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>2</TD> <TD>CLERK</TD> <TD>4150</TD> <TD>6</TD> <TD>7876</TD> <TD>ADAMS</TD> <TD>CLERK</TD> <TD>7788</TD> <TD>5/23/1987</TD> <TD>1100.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>3</TD> <TD>MANAGER</TD> <TD>8275</TD> <TD>7</TD> <TD>7698</TD> <TD>BLAKE</TD> <TD>MANAGER</TD> <TD>7839</TD> <TD>5/1/1981</TD> <TD>2850.00</TD> <TD> </TD> <TD>30</TD> </TR> <TR> <TD>3</TD> <TD>MANAGER</TD> <TD>8275</TD> <TD>8</TD> <TD>7566</TD> <TD>JONES</TD> <TD>MANAGER</TD> <TD>7839</TD> <TD>4/2/1981</TD> <TD>2975.00</TD> <TD> </TD> <TD>20</TD> </TR> <TR> <TD>3</TD> <TD>MANAGER</TD> <TD>8275</TD> <TD>9</TD> <TD>7782</TD> <TD>CLARK</TD> <TD>MANAGER</TD> <TD>7839</TD> <TD>6/9/1981</TD> <TD>2450.00</TD> <TD> </TD> <TD>10</TD> </TR> <TR> <TD>4</TD> <TD>PRESIDENT</TD> <TD>5000</TD> <TD>10</TD> <TD>7839</TD> <TD>KING</TD> <TD>PRESIDENT</TD> <TD> </TD> <TD>11/17/1981</TD> <TD>5000.00</TD> <TD> </TD> <TD>10</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>11</TD> <TD>7844</TD> <TD>TURNER</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>9/8/1981</TD> <TD>1500.00</TD> <TD>0.00</TD> <TD>30</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>12</TD> <TD>7654</TD> <TD>MARTIN</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>9/28/1981</TD> <TD>1250.00</TD> <TD>1400.00</TD> <TD>30</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>13</TD> <TD>7521</TD> <TD>WARD</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>2/22/1981</TD> <TD>1250.00</TD> <TD>500.00</TD> <TD>30</TD> </TR> <TR> <TD>5</TD> <TD>SALESMAN</TD> <TD>5600</TD> <TD>14</TD> <TD>7499</TD> <TD>ALLEN</TD> <TD>SALESMAN</TD> <TD>7698</TD> <TD>2/20/1981</TD> <TD>1600.00</TD> <TD>300.00</TD> <TD>30</TD> </TR> </TABLE> </body> </html>
mergeTD
对于合并单元格,这两种方式都不太满意,可是,也想不到更好的方法对此操作作封装。
如果童靴有更好的方法,请指点!!
Javascript横向/纵向合并单元格TD