用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");//清除多選