归档 标签 友链 关于

解决 render-html-to-pdf 分页截断的问题

用 html2canvas 和 jsPdf 库实现的网页导出 PDF 存在一个问题,即分页会将一些元素截断。目前的解决方案是对 body 的子元素遍历,每次计算累计高度和页面高度的差值,如果累计高度超出页面高度,则将超出的部分前插入一段空白,将其“挤”到下一页,这段空白的高度是页面高度减去上一次累计的高度。最后再 remove 掉插入的这些空白,恢复原貌。

但页面的实际高度和 html 的高度有一个映射,既不是 html 的高度,也不是 A4 纸的高度,而是渲染成 canvas 是高度,所以目前的方案是先渲染一次获取到 canvas 的高度,插入空白之后再渲染一次并输出 PDF。

var downPdf = document.getElementById("renderPdf");

downPdf.onclick = function() {
  downPdf.style.visibility = "hidden"; //点击时隐藏按钮,避免出现在 PDF 上

  //第一次渲染获取实际高度
  html2canvas(document.body, {
    onrendered: function(canvas) {
      var contentWidth = canvas.width;

      //一页 PDF 显示 html 页面生成的 canvas 高度;
      var pageHeight = (contentWidth / 595.28) * 841.89 - 30; //减一部分缓冲误差
      /* 根据屏幕宽度进行分页的适配 */
      var outerEles = $("#outer-part").children();
      var sumHeight = 0;

      outerEles.each(function() {
        var lastSumHeight = sumHeight;
        sumHeight += $(this).outerHeight(true);

        if (sumHeight > pageHeight) {
          $(this).before(
            '<div class="insert-block" style="height: ' +
              (pageHeight - lastSumHeight + 50) +
              'px"></div>'
          ); //加一部分缓冲误差
          sumHeight = $(this).outerHeight(true) + 50; //重新累计,并把缓冲的部分算到下一页的累计高度
        }
      });
      downloadPdf();
      downPdf.style.visibility = "visible"; //保存后显示按钮
      $(".insert-block").remove();
    }
  });
};

function downloadPdf() {
  //第二次渲染并输出 PDF
  html2canvas(document.body, {
    onrendered: function(canvas) {
      var contentWidth = canvas.width;
      var contentHeight = canvas.height;

      //一页 PDF 显示 html 页面生成的 canvas 高度;
      var pageHeight = (contentWidth / 595.28) * 841.89;
      //未生成 PDF 的 html 页面高度
      var leftHeight = contentHeight;
      //pdf页面偏移
      var position = 0;
      //a4 纸的尺寸[595.28,841.89],html 页面生成的 canvas 在 pdf 中图片的宽高
      var imgWidth = 595.28;
      var imgHeight = (595.28 / contentWidth) * contentHeight;

      var pageData = canvas.toDataURL("image/jpeg", 1.0);

      var pdf = new jsPDF("", "pt", "a4");

      //有两个高度需要区分,一个是 html 页面的实际高度,和生成 PDF 的页面高度(841.89)
      //当内容未超过 PDF 一页显示的范围,无需分页
      if (leftHeight < pageHeight) {
        pdf.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
      } else {
        while (leftHeight > 0) {
          pdf.addImage(pageData, "JPEG", 0, position, imgWidth, imgHeight);
          leftHeight -= pageHeight;
          position -= 841.89;
          //避免添加空白页
          if (leftHeight > 0) {
            pdf.addPage();
          }
        }
      }
      pdf.save("标题.pdf");
    }
  });
}

· 转载请注明 https://tangkaichuan.cn/solve-render-html-to-pdf-problem/