将HTML页面部分内容导出为PDF

之前写了一篇博文 JS 如何将 HTML 页面导出为 PDF
当时只是自己有个需求,只是导出一页PDF,写个了示例。

之后就有同学私信我问我怎么导出多页PDF。好吧,其实这些看文档画画图自己是可以写出来的。以后也可能有转换HTML导出多页的PDF需求,就决定写一个库 renderPDF 吧。

地址在这里:https://github.com/pwcong/how-transform-html-into-multipage-pdf

原理

因为依赖了 jsPDF 这个库,所以导出 PDF 就查阅 jsPDF 的相关文档。

通过查阅文档可知,jsPDF 提供添加新一页的 API 函数 addPage(),因此我考虑给过长的div分页就围绕它进行思考。

这里说明一下大概步骤:

  • 首先将要导出PDF的 div (这里命名为content) 渲染成canvas,获取该canvas的图片url数据 imgData

  • 新建div命名为 page 插入到 body 中:

    1. 设置style、class、id均与 content 一致,然后再继续下面的步骤
    2. 设置宽度为 content 的宽度,高度设置为计算后得出的pageHeight,这里源码如下:

          var pdfProportion = pdfFormat[format][0] / pdfFormat[format][1];
      
          var contentHeight = content.offsetHeight;
          var contentWidth = content.offsetWidth;
      
          var pageHeight = contentWidth / pdfProportion;
          var pageWidth = contentWidth;
      
           
           
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      其中 pdfFormat 为预定义对象, format 为输入的PDF格式

    3. 设置其背景为 url(imgData)
  • 接着判断contentHeight和pageHeight

    • 若前者小于后者说明不用分页,直接添加图片数据导出,源码如下:

          if(contentHeight < pageHeight){
      
              pdf.addImage(imgData, 'JPEG', 0, 0,pdfFormat[format][0],pdfFormat[format][1]/pageHeight*contentHeight);
      
              pdf.save(pdfName);
      
          }
           
           
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 若前者大于后者,则需要分页:

      1. 先求出页数 count ,循环次数为 count-1
      2. 设置 pagebackground 偏移
      3. 接着渲染page为canvas获取图片url数据 pageData 插入 pdf 对象中,pdf 对象执行 addPage() 函数
      4. 添加最后一页,因为最后一页高度可能和pageHeight大小不一致,因此设置 page 的高度为计算的得出的 lastPageHeight ,渲染成canvas获取图片数据插入 `pdf
      5. 导出保存,源码如下:

            var index = 0;
            var count = parseInt(contentHeight / pageHeight);
        
            var page = document.createElement("div");
        
            page.style.position = "absolute";
            page.style.width = contentWidth + "px";
            page.style.height = pageHeight + "px";
            page.style.backgroundImage = "url(" + imgData + ")";
            page.style.backgroundRepeat = "norepeat";
        
            document.body.appendChild(page);
        
            function addPage(i, onFinished){
        
                page.style.backgroundPositionY = -pageHeight * i + "px";
        
                html2canvas(page, {
        
                    onrendered: function(canvas) {
        
                        var pageData = canvas.toDataURL('image/jpeg');
        
                        pdf.addImage(pageData, 'JPEG', 0, 0,pdfFormat[format][0],pdfFormat[format][1]);
        
                        if(i + 1 < count){
                            pdf = pdf.addPage();
                            addPage(i + 1, onFinished);
                        }
                        else{
                            onFinished()
                        }
        
                    }
                });
        
            }
        
            addPage(index, function(){
        
                page.style.backgroundPositionY = -pageHeight * count + "px";
        
                var lastPageHeight = contentHeight % pageHeight;
                page.style.height = lastPageHeight + "px";
        
                html2canvas(page, {
        
                    onrendered: function(canvas) {
        
                        var pageData = canvas.toDataURL('image/jpeg');
        
                        pdf = pdf.addPage();
                        pdf.addImage(pageData, 'JPEG', 0, 0,pdfFormat[format][0], pdfFormat[format][1]/pageHeight*lastPageHeight);
        
                        document.body.removeChild(page);
        
                        onSuccess && onSuccess();
        
                        pdf.save(pdfName);
        
                    }
                });
        
        
            });
               
               
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43
        • 44
        • 45
        • 46
        • 47
        • 48
        • 49
        • 50
        • 51
        • 52
        • 53
        • 54
        • 55
        • 56
        • 57
        • 58
        • 59
        • 60
        • 61
        • 62
        • 63
        • 64
        • 65
  • 最后,body 删除名为 page div

写在后面

因为个人能力不足,这个方法在导出页数过多的PDF的时候(例如20页以上)会有明显的浏览器卡顿。
而且没有进行什么优化,导出的PDF有点模糊,这个大佬们若有解决方法可以私信哈。

还有这方法有点 dirty hack,其实最 smart hack 的方法是,直接js执行函数 window.print() ,导出的 PDF 效果也十分好,毕竟是浏览器的官方实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值