用html的table来布局,定制html模板,调用pd4ml生成要打印的pdf,为了方便添加了一个合并拆分单元格的方法,合并单元格来源于网络,可是有问题本身进行了修改。javascript
网上合并单元格源码以下:html
<table border="1"> <script> var s = ''; for (var i = 0; i < 10; i++) { s += '<tr>'; for (var j = 0; j < 10; j++) { s += '<td>' + i + '-' + j + '</td>'; } s += '</tr>'; } document.write(s); </script> </table> <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"></script> <script> //须要的样式 document.write('<style>.cannotselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;-khtml-user-select:none;user-select:none;}td.selected{background:#0094ff;color:#fff}</style>'); //jQuery表格单元格合并插件,功能和excel单元格合并功能同样,而且能够保留合并后的全部单元格内容到第一个单元格中 $.fn.tableMergeCells = function () { //***请保留原做者相关信息 //***power by showbo,http://www.w3dev.cn return this.each(function () { var tb = $(this), startTD, endTD, MMRC = { startRowIndex: -1, endRowIndex: -1, startCellIndex: -1, endCellIndex: -1 }; //初始化全部单元格的行列下标内容并存储到dom对象中 tb.find('tr').each(function (r) { $('td', this).each(function (c) { $(this).data('rc', { r: r, c: c }); }); }); //添加表格禁止选择样式和事件 tb.addClass('cannotselect').bind('selectstart', function () { return false }); //选中单元格处理函数 function addSelectedClass() { var selected = false, rc,t; tb.find('td').each(function () { rc = $(this).data('rc'); //判断单元格左上坐标是否在鼠标按下和移动到的单元格行列区间内 selected = rc.r >= MMRC.startRowIndex && rc.r <= MMRC.endRowIndex && rc.c >= MMRC.startCellIndex && rc.c <= MMRC.endCellIndex; if (!selected && rc.maxc) {//合并过的单元格,判断另外3(左下,右上,右下)个角的行列是否在区域内 selected = (rc.maxr >= MMRC.startRowIndex && rc.maxr <= MMRC.endRowIndex && rc.c >= MMRC.startCellIndex && rc.c <= MMRC.endCellIndex) ||//左下 (rc.r >= MMRC.startRowIndex && rc.r <= MMRC.endRowIndex && rc.maxc >= MMRC.startCellIndex && rc.maxc <= MMRC.endCellIndex) ||//右上 (rc.maxr >= MMRC.startRowIndex && rc.maxr <= MMRC.endRowIndex && rc.maxc >= MMRC.startCellIndex && rc.maxc <= MMRC.endCellIndex);//右下 } if (selected) this.className = 'selected'; }); var rangeChange = false; tb.find('td.selected').each(function () { //从已选中单元格中更新行列的开始结束下标 rc = $(this).data('rc'); t = MMRC.startRowIndex; MMRC.startRowIndex = Math.min(MMRC.startRowIndex, rc.r); rangeChange = rangeChange || MMRC.startRowIndex != t; t = MMRC.endRowIndex; MMRC.endRowIndex = Math.max(MMRC.endRowIndex, rc.maxr || rc.r); rangeChange = rangeChange || MMRC.endRowIndex != t; t = MMRC.startCellIndex; MMRC.startCellIndex = Math.min(MMRC.startCellIndex, rc.c); rangeChange = rangeChange || MMRC.startCellIndex != t; t = MMRC.endCellIndex; MMRC.endCellIndex = Math.max(MMRC.endCellIndex, rc.maxc || rc.c); rangeChange = rangeChange || MMRC.endCellIndex != t; }); //注意这里若是用代码选中过合并的单元格须要从新执行选中操做 if (rangeChange) addSelectedClass(); } function onMousemove(e) {//鼠标在表格单元格内移动事件 e = e || window.event; var o = e.srcElement || e.target; if (o.tagName == 'TD') { endTD = o; var sRC = $(startTD).data('rc'), eRC = $(endTD).data('rc'), rc; MMRC.startRowIndex = Math.min(sRC.r, eRC.r); MMRC.startCellIndex = Math.min(sRC.c, eRC.c); MMRC.endRowIndex = Math.max(sRC.r, eRC.r); MMRC.endCellIndex = Math.max(sRC.c, eRC.c); tb.find('td').removeClass('selected'); addSelectedClass(); } } function onMouseup(e) {//鼠标弹起事件 tb.unbind({ mouseup: onMouseup, mousemove: onMousemove }); if (startTD && endTD && startTD != endTD && confirm('确认合并?!')) {//开始结束td不相同确认合并 var tds = tb.find('td.selected'), firstTD = tds.eq(0), index = -1, t, addBR , html = tds.filter(':gt(0)').map(function () { t = this.parentNode.rowIndex; addBR = index != -1 && index != t; index = t; return (addBR ? '<br>' : '') + this.innerHTML }).get().join(','); tds.filter(':gt(0)').remove(); firstTD.append(',' + html.replace(/,(<br>)/g, '$1')); //更新合并的第一个单元格的缓存rc数据为所跨列和行 var rc = firstTD.attr({ colspan: MMRC.endCellIndex - MMRC.startCellIndex + 1, rowspan: MMRC.endRowIndex - MMRC.startRowIndex + 1 }).data('rc'); rc.maxc = rc.c + MMRC.endCellIndex - MMRC.startCellIndex; rc.maxr = rc.r + MMRC.endRowIndex - MMRC.startRowIndex; console.info(rc.maxc); console.info(rc.maxr); firstTD.data('rc', rc); } tb.find('td').removeClass('selected'); startTD = endTD = null; } function onMousedown(e) { var o = e.target; if (o.tagName == 'TD') { startTD = o; tb.bind({ mouseup: onMouseup, mousemove: onMousemove }); } } tb.mousedown(onMousedown); }); }; $('table').tableMergeCells(); </script>
他在初始化全部单元格的行列下标内容并存储到dom对象中是有问题的,他没有考虑到表格已存在跨行跨列的问题。java
修改初始化表格下标的方法以下:jquery
//给表格单元格标记索引 function setTdIndex($table) { var $trs = $table.find("tr"); //总行数 var all_row = $trs.length; //总列数 var all_col = 0; $trs.eq(0).children().each(function() { all_col += parseInt($(this).attr("colspan")) || 1; }); //单元格索引数组,用于标记单元格对应的索引是否被占用 var tdsIndex = []; for (var i = 0; i < all_row; i++) { tdsIndex[i] = new Array(); for (var j = 0; j < all_col; j++) { tdsIndex[i][j] = 0; } } //单元格索引站位,为了获取当前行下一个单元格索引位置 function tdsIndex_zw(i, j, colspan, rowspan) { for (var a = i; a < i + colspan; a++) { for (var b = j; b < j + rowspan; b++) { tdsIndex[b][a] = 1; } } } //获取第n行下一个单元格的索引 function getTdIndex(n) { for (var i = 0; i < all_col; i++) { if (tdsIndex[n][i] == 0) { return i; continue; } } } $trs.each(function(i) { $(this).children().each(function(j) { //td的索引,即td的x坐标 var x = getTdIndex(i); var rc = {r: i, c: x }; $(this).data('rc', rc); var td_colspan = parseInt($(this).attr("colspan") || 1); var td_rowspan = parseInt($(this).attr("rowspan") || 1); //在对象位置数组中站位 tdsIndex_zw(x, i, td_colspan, td_rowspan); //设置跨行跨列信息(单元格合并信息) if(td_rowspan >1){ rc.maxr = i + td_rowspan -1; } if(td_colspan >1){ rc.maxc = x + td_colspan -1; } }); }); }
修改后拆分单元格代码以下:web
<script type="text/javascript"> //给表格单元格标记索引 function setTdIndex($table) { var $trs = $table.find("tr"); //总行数 var all_row = $trs.length; //总列数 var all_col = 0; $trs.eq(0).children().each(function() { all_col += parseInt($(this).attr("colspan")) || 1; }); //单元格索引数组,用于标记单元格对应的索引是否被占用 var tdsIndex = []; for (var i = 0; i < all_row; i++) { tdsIndex[i] = new Array(); for (var j = 0; j < all_col; j++) { tdsIndex[i][j] = 0; } } //单元格索引站位,为了获取当前行下一个单元格索引位置 function tdsIndex_zw(i, j, colspan, rowspan) { for (var a = i; a < i + colspan; a++) { for (var b = j; b < j + rowspan; b++) { tdsIndex[b][a] = 1; } } } //获取第n行下一个单元格的索引 function getTdIndex(n) { for (var i = 0; i < all_col; i++) { if (tdsIndex[n][i] == 0) { return i; continue; } } } $trs.each(function(i) { $(this).children().each(function(j) { //td的索引,即td的x坐标 var x = getTdIndex(i); var rc = {r: i, c: x }; $(this).data('rc', rc); var td_colspan = parseInt($(this).attr("colspan") || 1); var td_rowspan = parseInt($(this).attr("rowspan") || 1); //在对象位置数组中站位 tdsIndex_zw(x, i, td_colspan, td_rowspan); //设置跨行跨列信息(单元格合并信息) if(td_rowspan >1){ rc.maxr = i + td_rowspan -1; } if(td_colspan >1){ rc.maxc = x + td_colspan -1; } }); }); } //须要的样式 document.write('<style>.cannotselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;-khtml-user-select:none;user-select:none;}td.selected{background:#0094ff;color:#fff}</style>'); //jQuery表格单元格合并插件,功能和excel单元格合并功能同样,而且能够保留合并后的全部单元格内容到第一个单元格中 $.fn.tableMergeCells = function () { //***请保留原做者相关信息 //***power by showbo,http://www.w3dev.cn return this.each(function () { var tb = $(this), startTD, endTD, MMRC = { startRowIndex: -1, endRowIndex: -1, startCellIndex: -1, endCellIndex: -1 }; //初始化全部单元格的行列下标内容并存储到dom对象中 /* tb.find('tr').each(function (r) { $('td', this).each(function (c) { $(this).data('rc', { r: r, c: c }); console.info($(this).data('rc')); }); }); */ setTdIndex(tb); //添加表格禁止选择样式和事件 tb.addClass('cannotselect').bind('selectstart', function () { return false }); //选中单元格处理函数 function addSelectedClass() { var selected = false, rc,t; tb.find('td').each(function () { rc = $(this).data('rc'); //判断单元格左上坐标是否在鼠标按下和移动到的单元格行列区间内 selected = rc.r >= MMRC.startRowIndex && rc.r <= MMRC.endRowIndex && rc.c >= MMRC.startCellIndex && rc.c <= MMRC.endCellIndex; if (!selected && rc.maxc) {//合并过的单元格,判断另外3(左下,右上,右下)个角的行列是否在区域内 selected = (rc.maxr >= MMRC.startRowIndex && rc.maxr <= MMRC.endRowIndex && rc.c >= MMRC.startCellIndex && rc.c <= MMRC.endCellIndex) ||//左下 (rc.r >= MMRC.startRowIndex && rc.r <= MMRC.endRowIndex && rc.maxc >= MMRC.startCellIndex && rc.maxc <= MMRC.endCellIndex) ||//右上 (rc.maxr >= MMRC.startRowIndex && rc.maxr <= MMRC.endRowIndex && rc.maxc >= MMRC.startCellIndex && rc.maxc <= MMRC.endCellIndex);//右下 } if (selected) this.className = 'selected'; }); var rangeChange = false; tb.find('td.selected').each(function () { //从已选中单元格中更新行列的开始结束下标 rc = $(this).data('rc'); t = MMRC.startRowIndex; MMRC.startRowIndex = Math.min(MMRC.startRowIndex, rc.r); rangeChange = rangeChange || MMRC.startRowIndex != t; t = MMRC.endRowIndex; MMRC.endRowIndex = Math.max(MMRC.endRowIndex, rc.maxr || rc.r); rangeChange = rangeChange || MMRC.endRowIndex != t; t = MMRC.startCellIndex; MMRC.startCellIndex = Math.min(MMRC.startCellIndex, rc.c); rangeChange = rangeChange || MMRC.startCellIndex != t; t = MMRC.endCellIndex; MMRC.endCellIndex = Math.max(MMRC.endCellIndex, rc.maxc || rc.c); rangeChange = rangeChange || MMRC.endCellIndex != t; }); //注意这里若是用代码选中过合并的单元格须要从新执行选中操做 if (rangeChange) addSelectedClass(); } function onMousemove(e) {//鼠标在表格单元格内移动事件 e = e || window.event; var o = e.srcElement || e.target; if (o.tagName == 'TD') { endTD = o; var sRC = $(startTD).data('rc'), eRC = $(endTD).data('rc'), rc; MMRC.startRowIndex = Math.min(sRC.r, eRC.r); MMRC.startCellIndex = Math.min(sRC.c, eRC.c); MMRC.endRowIndex = Math.max(sRC.r, eRC.r); MMRC.endCellIndex = Math.max(sRC.c, eRC.c); tb.find('td').removeClass('selected'); addSelectedClass(); } } function onMouseup(e) {//鼠标弹起事件 tb.unbind({ mouseup: onMouseup, mousemove: onMousemove }); } function hbdyg(){//合并单元格 if (startTD && endTD && startTD != endTD) {//开始结束td不相同确认合并 var tds = tb.find('td.selected'), firstTD = tds.eq(0), index = -1, t, addBR , html = tds.filter(':gt(0)').map(function () { t = this.parentNode.rowIndex; addBR = index != -1 && index != t; index = t; return (addBR ? '<br>' : '') + this.innerHTML; }).get().join(','); tds.filter(':gt(0)').remove(); //firstTD.append(',' + html.replace(/,(<br>)/g, '$1')); //更新合并的第一个单元格的缓存rc数据为所跨列和行 //console.log(firstTD.data('rc')); var rc = firstTD.attr({ colspan: MMRC.endCellIndex - MMRC.startCellIndex + 1, rowspan: MMRC.endRowIndex - MMRC.startRowIndex + 1 }).data('rc'); rc.maxc = rc.c + MMRC.endCellIndex - MMRC.startCellIndex; rc.maxr = rc.r + MMRC.endRowIndex - MMRC.startRowIndex; firstTD.data('rc', rc); //alert("合并完成!"); } //清除多选 qcdx(); } function qcdx(){//清除多选 tb.find('td').removeClass('selected'); startTD = endTD = null; } tb.on("hbdyg",hbdyg); tb.on("qcdx",qcdx); function onMousedown(e) {//鼠标按下事件 var o = e.target; if (o.tagName == 'TD') { startTD = o; tb.bind({ mouseup: onMouseup, mousemove: onMousemove }); } return false; } tb.mousedown(onMousedown); }); }; </script>
调用合并的方法以下:ajax
var selectTdTables = $('#dm_view table').tableMergeCells(); //合并单元格 function mm_hbdyg(){ selectTdTables.each(function () { $(this).trigger("hbdyg"); }); }
拆分单元格代码以下:数组
//拆分单元格 function mm_cfdyg(select_dom_id){ var $td = $("#"+select_dom_id);//当前选中的td var $tb = $td.parents('table:first');//td所在的table var $trs = $tb.find("tr");//table下全部的行 var rc = $td.data("rc");//单元格下标信息 //console.info(rc); var rowIndex = rc.r; var colIndex = rc.c; var td_rowspan = parseInt($td.attr("rowspan") || 1); var td_colspan = parseInt($td.attr("colspan") || 1); if(td_rowspan == 1 && td_colspan == 1){ return; } for(var i=rowIndex;i<rowIndex + td_rowspan;i++){//循环行 $trs.eq(i).children().each(function(n){//循环单元格 var td_rc = $(this).data("rc");//单元格下标 if(td_rc.c >= colIndex){//当前td索引(下标)大于或等于合并单元格的索引时,取前一个td,取不到前一个直接用当前的 //上一个单元格 var $sygdyg = $(this).prev().length == 0 ? $(this) : $(this).prev(); for(var j=colIndex;j<colIndex + td_colspan;j++){ var $newTd = $("<td></td>"); $sygdyg .after($newTd); } return false; } }); } $td.remove(); setTdIndex($tb);//删除后须要从新设置td下标 }
点击单元格时取消多选方法:缓存
$("#"+dom_id).parents('table:first').trigger("qcdx");//清除多选