• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

JS纯前端导出PDF和分页和使用window.print()保存PDF

武飞扬头像
只要两毛五
帮助31

最近由于项目要求需要将导出PDF类文件,其中涉及到固定表头,翻页,样式调整等问题 一开始选择了网上较多讲解的使用html2canvas.js和jspdf.js先转图片再转PDF的方法。

 var xsxf = document.getElementById("export_content");
 html2canvas(
     xsxf,
     //document.getElementById("export_content"),
     {
         dpi: 172,//导出pdf清晰度
         //proxy: "string",
         onrendered: function (canvas) {
             var contentWidth = canvas.width;
             var contentHeight = canvas.height;
             //一页pdf显示html页面生成的canvas高度;
             var pageHeight = 840;
             //var pageHeight = contentWidth / 575 * 840;
             //未生成pdf的html页面高度
             var leftHeight = contentHeight;
             //pdf页面偏移
             var position = 0;
             //html页面生成的canvas在pdf中图片的宽高(a4纸的尺寸[595.28,841.89])
             var imgWidth = 595.28;
             var imgHeight = 592.28 / contentWidth * contentHeight;
    
             var pageData;
             var pdf = new jsPDF('', 'pt', 'a4');
             //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
             //当内容未超过pdf一页显示的范围,无需分页
            if (leftHeight < pageHeight) {
                 pageData = canvas.toDataURL('image/jpeg', 1.0);
                 pdf.addImage(pageData, 'JPEG', 10, 5, imgWidth - 20, imgHeight - 10);
                
             } else {
                 while (leftHeight > 0) {
                     pageData = canvas.toDataURL('image/jpeg', 1.0);
                     pdf.addImage(pageData, 'JPEG', 10, position   5, imgWidth - 20, imgHeight - 10)
                     leftHeight -= pageHeight;
                     position -= 841.89;
                     //避免添加空白页
                     if (leftHeight > 0) {
                         pdf.addPage();
                     }
                 }
             }
             pdf.save(filename);
         },
         //背景设为白色(默认为黑色)
         background: "#fff"
     });
学新通

但很快发现当表格数据量大时出现翻页问题,所以试着先将表头固定数据取出,表体数据进行分割拼接表头

 //大于一页分页表头固定
        function reFullHtml(wb, filename, _tableHead, rowNum, pageHeight) {
            var tableH = document.querySelector('#table_content').scrollHeight   70;
            var miH = (pageHeight - tableH);       //详细
            var trL = $('#mini-grid-table1 > tbody>tr').length;
            var max = parseInt(miH / 34);
            var firstNum = rowNum - 2   max;

            var page = Math.ceil(trL / max);
            var brhtml = "</table></br></br></br></br></br>";
            //PL表尾
            if (rowNum == 12 && firstNum > (trL   rowNum - 5)) {
                firstNum = trL   rowNum - 6;
                page = Math.ceil(trL / (max - 5));
                brhtml = brhtml   "</br></br></br></br></br></br></br></br></br>";
            }
            //CI表尾(特殊德国小家电)
            if (rowNum == 14 && firstNum > (trL   rowNum - 1)) {
                firstNum = trL   rowNum - 2;
                page = Math.ceil(trL / (max - 1));
                brhtml = brhtml   "</br></br>";
            }
            //判断一页内行数高度 表头高是否大于页高
            if ((firstNum - rowNum) * 34   75 > miH) {
                firstNum -= 1;
                brhtml = '</table></br></br></br></br></br></br></br>';
            }
            var beforNum = firstNum;
            var newWb = wb;
            var pNum = firstNum - rowNum - 2;
            var syNum = pageHeight - (pNum   1) * 34 - tableH;
            var nbrHtml = "</table>"
            for (var c = 0; c < Math.ceil(syNum / 20); c  ) {
                nbrHtml  = "</br>"
            }
            for (var i = 0; i < page - 1; i  ) {
                if ((firstNum - beforNum) * 34   75 > miH) {
                    firstNum -= 1;
                    brhtml = '</table></br></br></br></br></br></br></br>';
                }
                beforNum = firstNum;
                var reg = "<tr><td style='text-align: center; border-bottom: 1px solid #000000;  border-right: 1px solid #000000; font-size: 10px; font-family: 微软雅黑; word-wrap:break-word; height:33px;' t='[a-z]' id='sjs-A"   firstNum   "'>.*";
                var res = newWb.match(reg);
                if (res != null) {
                    if (res.length > 0) {
                        var newHead = newWb.replace(res[0], brhtml);
                        newWb = newHead   _tableHead   res[0];
                    }
                }
                firstNum  = pNum;
                brhtml = nbrHtml;
            }
            if (firstNum < (trL   rowNum)) {
                if (rowNum == 12) {
                    firstNum = trL   rowNum - 6;
                    brhtml = "</table></br></br></br></br></br></br></br></br></br></br></br></br></br>";
                }
                else if (rowNum == 14) {
                    firstNum = trL   rowNum - 2;
                    brhtml = "</table></br></br></br></br></br></br>";
                }
                var reg1 = "<tr><td style='text-align: center; border-bottom: 1px solid #000000;  border-right: 1px solid #000000; font-size: 10px; font-family: 微软雅黑; word-wrap:break-word; height:33px;' t='[a-z]' id='sjs-A"   firstNum   "'>.*";
                var res1 = newWb.match(reg1);
                if (res1 != null) {
                    if (res1.length > 0) {
                        var newHead = newWb.replace(res1[0], brhtml);
                        newWb = newHead   _tableHead   res1[0];
                    }
                }
            }
            var xsxf = document.getElementById("export_content");
            xsxf.innerHTML = "</br>"    newWb;
            rowNum = 1;
            if (newWb != "") {
                //var pageWidth = document.querySelector("#mini-grid-table1").scrollWidth;

                for (var p = 0; p < document.querySelectorAll("#sjs-A1").length; p  ) {
                    document.querySelectorAll("#sjs-A1")[p].width = (pageWidth - 20)   "px";

                    document.querySelectorAll("#sjs-A5")[p].width = (pageWidth - 20) / 2   "px";
                    document.querySelectorAll("#sjs-E5")[p].width = (pageWidth - 20) / 2   "px";

                }
                downPDF(newWb, filename, _tableHead, rowNum);
            }

        }
学新通

分页解决完毕后,业务部门使用后反馈PDF过于模糊和数据无法复制,无奈寻找其他方法。
最后确定使用window.print()原生打印方法来保存。
其中碰到几个坑:
1、当表格宽度大于A4纸时,表格列宽会被挤压变现导致之前设置的列宽无效从而使分页出现问题
2、分页容纳行数算法和使用wp打印显示行数不一致,固尝试多次后固定行数
解决方案:
1、分页属性:style=‘page-break-after:always’ 分页属性 table 加上后会自动分页
2、设置表格宽度,其中表格宽最大设置到1000,大于1000时会变形

table {
  width:750px;
}

3、特殊列设置固定宽(列文字多的),其他使用百分比

function downPDF(wb, filename, _tableHead, rowNum, dataNum) {
	var xsxf = document.getElementById("export_content");
	  html2canvas(
	      xsxf,
	      //document.getElementById("export_content"),
	      {
	          //dpi: 172,//导出pdf清晰度
	          dpi: 144,
	          //proxy: "string",
	          onrendered: function (canvas) {
	              var contentWidth = canvas.width;
	              var contentHeight = canvas.height;
	              //一页pdf显示html页面生成的canvas高度;
	              var pageHeight = 840;
	              //var pageHeight = contentWidth / 575 * 840;
	              //未生成pdf的html页面高度
	              var leftHeight = contentHeight;
	              //pdf页面偏移
	              var position = 0;
	              //html页面生成的canvas在pdf中图片的宽高(a4纸的尺寸[595.28,841.89])
	              var imgWidth = 595.28;
	              var imgHeight = 592.28 / contentWidth * contentHeight;
	              var pageData;
	              var pdf = new jsPDF('', 'pt', 'a4');
	              if (leftHeight > pageHeight) {
	                  if (rowNum != 1) {
	                      reFullHtml(wb, filename, _tableHead, rowNum, dataNum);
	                      return;
	                  }
	              }
	              //20210826 hsj 原转PDF转图片失真严重,直接调用window打印方法保存
	              //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
	              //当内容未超过pdf一页显示的范围,无需分页
	              //if (leftHeight < pageHeight) {
	              //    pageData = canvas.toDataURL('image/jpeg', 1.0);
	              //    pdf.addImage(pageData, 'JPEG', 10, 5, imgWidth - 20, imgHeight - 10);
	                 
	              //} else {
	              //    while (leftHeight > 0) {
	              //        pageData = canvas.toDataURL('image/jpeg', 1.0);
	              //        pdf.addImage(pageData, 'JPEG', 10, position   5, imgWidth - 20, imgHeight - 10)
	              //        leftHeight -= pageHeight;
	              //        position -= 841.89;
	              //        //避免添加空白页
	              //        if (leftHeight > 0) {
	              //            pdf.addPage();
	              //        }
	              //    }
	              //}
	              //pdf.save(filename);
	              window.print();
	          },
	          //背景设为白色(默认为黑色)
	          background: "#fff"
	      });
}
学新通
  //大于一页分页表头固定
        function reFullHtml(wb, filename, _tableHead, rowNum, dataNum) {
            var trL = $('#mini-grid-table1 > tbody>tr').length;
            var max = 20;
            if (dataNum>10) {
                max = 27;
            }
            else if (dataNum == 10){
                max = 25;
            }
            else if (dataNum >7) {
                max = 22;
            }
            var firstNum = rowNum   2   max;
            var page = Math.ceil(trL / max);
            var brhtml = "</table>";
            var newWb = wb;
            for (var i = 0; i < page - 1; i  ) {
                var reg = "<tr><td style='text-align: center; border-bottom: 1px solid #000000;  border-right: 1px solid #000000; font-size: 10px; font-family: 微软雅黑; word-wrap:break-word; height:33px;' t='[a-z]' id='sjs-A"   firstNum   "'>.*";
                var res = newWb.match(reg);
                if (res != null) {
                    if (res.length > 0) {
                        var newHead = newWb.replace(res[0], brhtml);
                        //style='page-break-after:always' 分页属性
                        newWb = newHead   "</div><div style='page-break-after:always'>"   _tableHead   res[0];
                    }
                }
                else {
                    if (rowNum == 12) {
                        firstNum = trL   rowNum - 5;
                        brhtml = "</table>";
                    }
                    else if (rowNum == 14) {
                        firstNum = trL   rowNum - 1;
                        brhtml = "</table>";
                    }
                    var reg1 = "<tr><td style='text-align: center; border-bottom: 1px solid #000000;  border-right: 1px solid #000000; font-size: 10px; font-family: 微软雅黑; word-wrap:break-word; height:33px;' t='[a-z]' id='sjs-A"   firstNum   "'>.*";
                    var res1 = newWb.match(reg1);
                    if (res1 != null) {
                        if (res1.length > 0) {
                            var newHead = newWb.replace(res1[0], brhtml);
                            newWb = newHead   "</div><div style='page-break-after:always'>"   _tableHead   res1[0];
                        }
                    }
                }
                firstNum  = max;
            }
            if (firstNum < (trL   rowNum)) {
                if (rowNum == 12) {
                    firstNum = trL   rowNum - 5;
                    brhtml = "</table>";
                }
                else if (rowNum == 14) {
                    firstNum = trL   rowNum - 2;
                    brhtml = "</table>";
                }
                var reg1 = "<tr><td style='text-align: center; border-bottom: 1px solid #000000;  border-right: 1px solid #000000; font-size: 10px; font-family: 微软雅黑; word-wrap:break-word; height:33px;' t='[a-z]' id='sjs-A"   firstNum   "'>.*";
                var res1 = newWb.match(reg1);
                if (res1 != null) {
                    if (res1.length > 0) {
                        var newHead = newWb.replace(res1[0], brhtml);
                        newWb = newHead   "</div><div style='page-break-after:always'>"   _tableHead   res1[0];
                    }
                }
            }
            var xsxf = document.getElementById("export_content");
            xsxf.innerHTML = "<div style='page-break-after:always'>"   newWb   "</div>";
            rowNum = 1;
            if (newWb != "") {
                if (dataNum >= 10) {
                    for (var n = 0; n < document.querySelectorAll("table").length; n  ) {
                        document.querySelectorAll("table")[n].style.width = '900px';
                        document.querySelectorAll("table")[n].style.width = '900px';
                    }
                }
                for (var p = 0; p < document.querySelectorAll("#sjs-A1").length; p  ) {
                    document.querySelectorAll("#sjs-A1")[p].width = (pageWidth - 20)   "px";
                    document.querySelectorAll("#sjs-A5")[p].width = (pageWidth - 20) / 2   "px";
                    document.querySelectorAll("#sjs-E5")[p].width = (pageWidth - 20) / 2   "px";
                    
                }
                downPDF(newWb, filename, _tableHead, rowNum);
            }
           
        }
学新通

效果
学新通
学新通
总结:总体来说还是使用最开始导出PDF的思路,先在html中解决分页问题后导出,不过放弃转成图片方式而直接使用原生方法。整体解决了分页问题和不清晰无法复制等问题。

参考资料:https://www.jianshu.com/p/4d65857ffe5e
https://segmentfault.com/a/1190000018701596

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhffhjji
系列文章
更多 icon
同类精品
更多 icon
继续加载