拿到这个需求,我已经蛋碎了一地,经过N天的攻克,终于是把它搞定了,只是不知道会不会在某种情况下出现BUG。表示我心虚没有敢做太多的测试....
----------------------------------------------------------废话分割线-----------------------------------------------------------
注:我们的系统是基于ligerui这个一堆bug的插件的。
详细需求:
1.任意一个表格,行高不均匀且不相等;
2.数字、公式等,不能换行;
3.A3、A4纸横向打印,用户可选;
4.JavaScript实现
5.每页都要有表头、总记录数、当前页和总页数
整体思路:
1.js无法获取打印机的信息,所以,要用户在我们系统中选择好纸张大小,然后打印的时候再选一次,个人认为这个要自动适配并不容易,反正我的是手动选的。
2.数字、公式不能换行,如果表格横向特别长,就不能使用css:word-break进行强制换行,只能由它默认的去换行。
3.js打印肯定是先新建个空白的页面,然后把东西展示出来,用Jquery.Print这个插件调用浏览器的所见即所得这种方式去打印。
4.页面上有个隐藏的模版,规定表格、标题、汇总信息的样式,并给定Id,或者Class,以便后续Jquery取得时候比较方便(后面我贴源码出来)。
5.先把整个表格都展示出来,给定它宽度(A3/A4纸的宽度)之后,它的每一行的高度就确定了。
6.这时候去遍历这个表格,可以把每一行的高度都取出来,循环的累加它,当高度超过纸张高度时,就记录下来这个开始行数(startLine)和结束行数(endLine),然后Jquery创建一个表格,从步骤4的表格中,把它的表头取出来,Append到新创建的表格中,然后根据开始行数和结束行数,把这些tr取出来,也Append到新创建的表格中。
7.从模板中取出来标题、汇总信息等的模版,然后把它替换成想要的内容之后,append到上面的表格的前后。
8.打印设置纸张大小思路:给个打印设置的弹出层,上面有A3/A4两个单选按钮,选完,点击页面上的确定按钮,我把这个选中值存到cookie里面,打印的时候,从cookie里面取出来,然后去给定纸张的高度和宽度。
以上就是整体的思路,下面贴代码(注:css其实也是蛮重要的,但是css前面不是我写的,后面我忘记改了哪些东西了,所以贴出来也没卵用)。
1.打印所使用的HTML模板
1 217 18 19 46
2.jquery.printTable.js,这个是网上找的,我改了一些,它默认里面的总页数算法是有问题的,我做了调整,我还新增了列宽的指定等,具体我也记不清了,有兴趣的可以对比一下,我完了以附件的形式上传这个js插件。
1 /** 2 * jquery 表格打印插件 3 * 4 * 作者: LiuJunGuang 5 * 日期:2013年6月4日 6 * 分页样式(需要自定义): 7 * @media print { 8 * .pageBreak { page-break-after:always; } 9 * } 10 * 使用例子: 11 * $(function(){ 12 * $("#tabContent").printTable({ 13 * mode : "rowNumber", 14 * header : "#headerInfo", 15 * footer : "#footerInfo", 16 * pageNumStyle : "第#p页/共#P页", 17 * pageNumClass : ".pageNum", 18 * pageSize : 10 19 * }); 20 * }); 21 * 注意事项: 22 * 使用时注意表格中要使用 thead 和 tbody区分出标题头与表格内容,否则可能出现错误 23 * 24 * 参数说明: 25 * options are passed as json (json example: { rowHeight : "rowHeight", header : ".tableHeader",}) 26 * 27 * {OPTIONS} | [type] | (default), values | Explanation 28 * ---------------- | --------- | -----------------------------| ----------- 29 * @mode | [string] | ("rowHeight"),rowNumber | 分页模式,按行高分页或按行数分页 30 * @header | [string] | (".tableHeader") | 页面开始处要添加的内同 31 * @footer | [string] | (".tableFooter") | 页面结束要添加的内容 32 * @pageSize | [number] | (30) | 自动分页行数,按行高分页时改参数无效 33 * @breakClass | [string] | ("pageBreak") | 分页插入符class,需要定义分页样式 34 * @pageNumStyle | [string] | "#p/#P" | 页码显示样式,#p当前页,#P总页数 35 * @pageNumClass | [string] | ".pageNumClass" | 页码class样式,用于设值(使用text方法设置) 36 * @startPage | [number] | (1) | 第一页起始页码 37 * @pageHeight | [number] | (297) | 页面高度,单位像素 38 * @topMargin | [number] | (15) | 上边距高度,单位像素 39 * @bottomMargin | [number] | (15) | 低边距高度,单位像素 40 */ 41 (function($) { 42 var modes = { rowHeight : "rowHeight", rowNumber : "rowNumber" }; 43 //默认参数 44 var defaults = { 45 mode : modes.rowHeight, 46 header : ".tableHeader", 47 footer : ".tableFooter", 48 pageSize : 30, 49 breakClass : "pageBreak", 50 pageNumStyle : "第#p页/共#Total#页", 51 pageNumClass : ".pageNumClass", 52 startPage : 1, 53 pageHeight : 720, //A4纸默认在win7下Web中的dpi是96,所以A4纸在win7下的大小换算成像素应该是794×1123,这里留空白 54 topMargin : 50, 55 bottomMargin : 50, 56 width : 1100, //留白100px 57 totalNumClass : "floatRight", 58 containsId :"#print-content" 59 }; 60 var settings = {};//global settings 61 var rowCount = 0;//行总数 62 var pageCount = 0;//页总数 63 var currentPage = 0;//当前页 64 var $header = null;//表格头 65 var $content = null;//表格内容 66 var $footer = null;//表格尾 67 var $table = null; 68 var $tbodyTr = null; 69 var totalPageCount = 0;//总页数 70 $.fn.printTable = function( options ) { 71 $.extend( settings, defaults, options ); 72 $table = $(this); 73 $tbodyTr = $table.find("tbody tr"); 74 var $container = $(settings.containsId); 75 totalPageCount = 0; 76 //$(settings.totalNumClass).text($tbodyTr.length); 77 //$table.width("720pt"); 78 switch ( settings.mode ){ 79 case modes.rowHeight : 80 rowHeightPage();//行高分页 81 $container.html($container.html().replace(/#Total/g,totalPageCount)) ; 82 break; 83 case modes.rowNumber : 84 rowNumberPage();//行数分页 85 } 86 }; 87 //获取页总数 88 $.fn.printTable.getStartPage = function(startPage) { 89 return getPageStyle(startPage , pageCount); 90 }; 91 //行高分页 92 function rowHeightPage() { 93 var contentHeight = initHeightPage(); 94 getContentColne(); 95 beginPageByHeight(contentHeight); 96 hidenContent(); 97 } 98 99 100 //行数分页101 function rowNumberPage(){102 initNumberPage();103 getContentColne();104 beginPageByNumber();105 hidenContent();106 }107 108 //按行高分页109 function beginPageByHeight(contentHeight){110 var totalHeight = 0;111 var startLine = 0;112 $tbodyTr.each(function(i){113 var cHeight = $(this).outerHeight(true);114 $(this).height(cHeight);115 if ((totalHeight + cHeight) < contentHeight) {116 totalHeight += cHeight;117 if(i == $tbodyTr.length -1){118 newPage(i + 1);119 }120 }else{121 newPage(i);122 }123 });124 125 function newPage(index){126 createPage(startLine,index);127 currentPage++;128 totalPageCount++;129 startLine = index;130 totalHeight = 0;131 }132 }133 134 //初始化高度分页信息135 function initHeightPage(contentHeight){136 var contentHeight = initContentHeight();137 currentPage = 0 + settings.startPage;138 pageCount = Math.ceil($table.find("tbody").outerHeight(true)/contentHeight) + settings.startPage - 1;//初始化总页数139 rowCount = $tbodyTr.length; //初始化总记录数140 return contentHeight;141 }142 143 144 //初始化内容高度145 function initContentHeight(){146 var headerHeight = $(settings.header).outerHeight(true);147 var footerHeight = $(settings.footer).outerHeight(true);148 $table.find("thead td").each(function(i) {149 var cWidth = $(this).outerWidth(true);150 $(this).width((cWidth / 96 * 72) + "pt");151 });//给表头一个宽度,但是貌似打印的时候不顶卵用152 var theadHeight = $table.find("thead").outerHeight(true);153 var tableHeight = settings.pageHeight - settings.topMargin - settings.bottomMargin ;154 var tbodyHeight = tableHeight - theadHeight- headerHeight - footerHeight;155 return tbodyHeight;156 }157 //初始化分页基本信息158 function initNumberPage(){159 rowCount = $tbodyTr.length;//初始化总记录数160 pageCount = Math.ceil(rowCount/settings.pageSize) + settings.startPage - 1;//初始化总页数161 currentPage = 0 + settings.startPage;162 }163 164 //开始分页165 function beginPageByNumber(){166 var startLine = 1;//开始行号167 var offsetLine = 0;//偏移行号168 for(var i = settings.startPage; i <= pageCount ;i++ ){169 currentPage = i;170 startLine = settings.pageSize* (currentPage - settings.startPage);171 offsetLine = (startLine + settings.pageSize) > rowCount ? rowCount : startLine + settings.pageSize;172 createPage(startLine,offsetLine);173 };174 }175 //创建新的一页176 function createPage(startLine, offsetLine) {177 var $pageHeader = $header.clone();178 var $pageContent = $content.clone().append(getTrRecord(startLine, offsetLine));179 var $pageFooter = $footer.clone();180 $pageFooter.find(settings.pageNumClass).text(getPageStyle(currentPage , pageCount));//页码显示格式181 if(offsetLine == rowCount){182 $table.before($pageHeader).before($pageContent).before($pageFooter);183 }else{184 $table.before($pageHeader).before($pageContent).before($pageFooter).before(addPageBreak());185 }186 }187 188 //添加分页符189 function addPageBreak(){190 return " ";191 }192 193 //获取分页样式194 function getPageStyle(currentPage , pageCount){195 var numStr = settings.pageNumStyle;196 numStr = numStr.replace(/#p/g,currentPage);197 //numStr = numStr.replace(/#P/g,pageCount);198 return numStr;199 }200 201 202 //获取记录203 function getTrRecord(startLine,offsetLine){204 return $tbodyTr.clone().slice(startLine,offsetLine);205 }206 //获取内容207 function getContentColne(){208 $header = $(settings.header).clone().removeAttr("id");209 $content = $table.clone().find("tbody").remove().end().removeAttr("id");210 $footer = $(settings.footer).clone().removeAttr("id");211 }212 //隐藏原来的数据213 function hidenContent(){214 $(settings.header).hide();215 $table.hide();216 $(settings.footer).hide();217 }218 })(jQuery);
3.打印预览的实现js
1 var win = null; 2 // var winPrintSetting = null; 3 //打印预览函数 4 function grid_PrintView() { 5 if (win) { 6 win.show(); 7 return; 8 } 9 var grid = $(".listgrid:first").ligerGrid(); 10 // var oldpageSize = grid.options.pageSize; 11 // grid.options.pageSize = grid.filteredData.Rows.length; 12 // grid.reload(); 13 14 $(".Printtable:gt(0)").remove(); 15 $(".header:gt(0)").remove(); 16 $(".headInfo:gt(0)").remove(); 17 $(".signatureArea:gt(0)").remove(); 18 $(".header h2").text(TABData[0].标题); 19 $(".headInfo .floatRight").text("记录总数:" + grid.currentData.Rows.length); 20 $(".Printtable:last").find("thead").html(""); 21 $(".Printtable:last").find("tbody").html("");//清空第一个表格的thead和tbody 22 $(".Printtable:last thead").append($(".l-grid2 .l-grid-header-inner tbody")[0].innerHTML); 23 $(".Printtable:last tbody").append($(".l-grid2 .l-grid-body-table tbody")[0].innerHTML);//重新把所有的数据给到这个表格 24 $(".Printtable:last *").removeAttr("class"); 25 $(".Printtable:last *").removeAttr("style");//清理掉样式 26 $(".header").show(); 27 $("#tabContent").show(); 28 win = $.ligerDialog.open( 29 { height: 794, target: $("#print-content"), width: 1090, showMax: true, showToggle: true, showMin: true, isResize: true, modal: false, title: '打印预览 ', slide: true }); 30 win.max(); 31 ChangePages(); 32 } 33 //把一个连起来的表格拆分 34 function ChangePages() { 35 var height = 930; 36 var paper_size = $.cookie('paper_size'); 37 if (paper_size == 'A4') { 38 height = 580; 39 $(".print-content").width("700pt"); 40 } else { 41 height = 930; 42 $(".print-content").width("1000pt"); 43 } 44 $(".Printtable:last").printTable({ 45 mode: "rowHeight", 46 header: "#header", 47 //footer: "#footerInfo",signatureArea 48 footer: "#footerInfo", 49 pageNumStyle: "第#p页/共#Total页", 50 pageNumClass: ".pageNum", 51 pageHeight: height, //A4:580 ,A3 930 52 startPage: 1, 53 totalNumClass: ".floatRight", 54 containsClass: "#print-content" 55 }); 56 } 57 //改变打印纸大小时 58 function ChangePaper() { 59 var grid = $(".listgrid:first").ligerGrid(); 60 $(".Printtable:gt(0)").remove(); 61 $(".header:gt(0)").remove(); 62 $(".signatureArea:not(:last)").remove();//清理当前已经分页分好的表格,把除了第一个表格外的所有表格都干掉 63 $(".header h2").text(TABData[0].标题); 64 $(".headInfo .floatRight").text("记录总数:" + grid.currentData.Rows.length); 65 $(".pageBreak").remove(); 66 $(".Printtable:first").find("thead").html(""); 67 $(".Printtable:first").find("tbody").html("");//清空第一个表格的thead和tbody 68 $(".Printtable:first thead").append($(".l-grid2 .l-grid-header-inner tbody")[0].innerHTML); 69 $(".Printtable:first tbody").append($(".l-grid2 .l-grid-body-table tbody")[0].innerHTML);//重新把所有的数据给到这个表格 70 $(".Printtable:first *").removeAttr("class"); 71 $(".Printtable:first *").removeAttr("style");//清理掉样式 72 $(".header").show(); 73 $(".signatureArea").show(); 74 ChangePages(); 75 } 76 77 var winPrintSetting = null; 78 //纸张大小设置 79 function PrintSetting() { 80 var paper_size = $.cookie('paper_size'); 81 if (paper_size) { 82 $("input[name='paper_size'][value='" + paper_size + "']").attr("checked", true); 83 } else { 84 $.cookie('paper_size', 'A3', { expires: 30 }); 85 $("input[name='paper_size'][value='A3']").attr("checked", true); 86 } 87 win.min(); 88 89 if (winPrintSetting) { 90 winPrintSetting.show(); 91 } else { 92 winPrintSetting = $.ligerDialog.open({ 93 target: $("#print-setting"), 94 height: 200, 95 width: 300, 96 modal: true, 97 title: "打印设置", 98 allowClose: false, 99 isHidden:true,100 buttons: [{ text: '确定', onclick: function (item, dialog) {101 var paperSize = $("[name=paper_size]:checked").val();102 $.cookie('paper_size', paperSize, { expires: 30 });103 win.max();104 win.active();105 ChangePaper();106 dialog.hide();107 }108 }, { text: '取消', onclick: function (item, dialog) {109 win.max();110 win.active();111 dialog.hide();112 }113 }]114 });115 }116 117 }
4.没了
注意事项:改变纸张之后调整现有页面的宽度、高度的时候,记得把现有的DOM都给清掉,只留一个模版的table,然后重新来。指定宽度高度的时候,能用pt的就用pt,实在用不了的再用px,哪怕用个mm,cm都比px强,因为打印机最后认的是长度,而不是像素点,建议页面上所有的字体大小都用pt来指定。
在谷歌浏览器中,使用默认页边距的情况下,A3、A4纸比较合适的尺寸:
A3:1000pt *930px
A4:700pt*580px
这个因为宽度是你用jquery去指定的,所以能用pt去指定,但是你在分页时算高度时,用Jquery获取出来只能获取到像素,所以,这就是为什么要用奇葩的pt*px这种组合的原因。这样子反正我的是大部分没有什么问题,如果不行稍微微调一点就可以了
这是我网上找的Jquery.printTable.js
效果图N张: