jspdf-html2canvas生成多页pdf防截断处理(包含代码)

最近遇到一个需求,需要把内容下载生成pdf文件,我采用的是jspdf+html2canvas,但转换过程中内容总是会被截断,就很难受...

技术栈:vue2+jspdf+html2canvas

一,解决思路:

判断给被截断的地方添加空白的div元素

1.拿到所有需要预防被截断的元素

2.根据页面高度进行判断

3.创建div插入进去

从页面布局考虑分为俩中情况,1.页面布局固定,2.页面布局不固定

1.页面布局固定

如果生成的网页按照与pdf固定的比例刚好是不会被截断的效果就直接解决问题了。因此只需要网页按每页pdf的宽高映射一个固定的宽高,然后按照这个固定的宽高放置不超过该大小的dom,生成pdf的代码只需要进行正常的多页pdf生成即可

2.页面布局不固定

如果网页无法进行固定大小的布局,在生成pdf的时候则需要计算每页pdf放置的dom达到刚好不被截断的边界情况。考虑到dom可能嵌套层级较多,并且对一些属性节点、文本节点不好计算高度,可以给dom元素添加标识来表示是否需要计算高度

二,代码实现
1.下载
npm install html2canvas --save
npm install jspdf --save
 2.引入
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
3.1页面布局固定逻辑代码
 printPdf() {
      /*pdf出现分页时图片文宁被截断问题解决: 获取所有的需要下载的外层盒子,
      循环处理这些盒子,获取当前盒子距离顶部的高度offsetTop加上盒子的高度是否大于a4纸的高度,
      如果大于就在之前插入空白盒子,把内容挤下去。*/
      const A4WIDTH = 592.28;
      const A4HEIGHT = 841.89;

      let target = document.getelementByid(pdfDom);
      let pageHeight = target.scrollwidth / A4WIDTH * A4HEIGHT;

      // 获取分割dom,此处为class类名为item的dom
      let lableListID = target.getelementsByclassName('item')
      // 进行分制操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
      for (let i = o; i < lableListID.length; i++) {
        let multiple = Math.ceil((lablelistID[i].offsetTop + lablelistID[i].offsetHeight) / pageHeight);
        if (isSplit(lableListID, i, multiple * pageHeight)) {
          let divParent = lableListID[i].parentNode; // 获取该div的父节点
          let newNode = document.createElement(' div');
          newNode.className = "emptyDiv";
          newNode.style.background = "#01195e";
          let _H = multiple * pageHeight - (lablelistID[i].offsetTop + lablelistID[i].offsetHeight);
          newNode.style.height = _H + 30 + 'px';
          newNode.style.width = '100%';
          let next = lableListID[i].nextsibling; // 获取div的下一个兄弟节点
          // 判断兄弟节点是否存在
          console.log(next);
          if (next) {
            // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
            divparent.insertBefore(newNode, next);
          } else {
            // 不存在则直接添加到最后,appendchild默认添加到divParent的最后
            divparent.appendChild(newNode);
          }
        }
      }
      /* 执行下载并打印PDF的方法 */
      this.pdfs(pdfDom, title);
    },

  // 判断是否需要添加空白div
    isSplit(nodes, index, pageHeight) {
      // 计算当前这块dom是否跨越了a4大小,以此分制
      if (nodes[index].offsetTop + nodes[index].offsetHeight < pageleight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {
        return true;
      }
      return false;
    },

//下载并打印PDF
 pdfs() {
      //div内部滚动导致内容不全处理
      document.getElementById('app').style.height = 'auto';
      setTimeout(() => {
        html2canvas(document.getElementById('reportBox'), {
          background: '#01195e',
          allowTaint: true,
          useCORS: true,
          // height: document.getElementById('upload').scrollHeight,
          // windowHeight: document.getElementById('upload').scrollHeight
        }).then((canvas) => {
          // console.log(canvas);
          // var contentWidth = canvas.width;
          // var contentHeight = canvas.height;
          var contentWidth = parseInt(canvas.style.width) * 2;
          var contentHeight = parseInt(canvas.style.height) * 2;

          // console.log('contentWidth', contentWidth);
          // console.log('contentHeight', contentHeight);
          //一页pdf显示html页面生成的canvas高度;
          var pageHeight = (contentWidth / 592.28) * 841.89;
          //未生成pdf的html页面高度
          var leftHeight = contentHeight;
          //页面偏移
          var position = 0;
          //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
          var imgWidth = 595.28;
          var imgHeight = (592.28 / contentWidth) * contentHeight;
          // console.log('imgHeight', imgHeight);
          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 > 100) {
                pdf.addPage();
              }
            }
          }
        });
      }, 300);
    },
3.2页面布局不固定逻辑代码

通过页面在浏览器的位置,计算出每一页需要分页的位置,对获取的DOM元素进行循环判断添加空白div

    getAllNodes() {
      // 需判断分页的节点
      const lableListID = document.querySelectorAll('.ifPagingNode');
      // 获取到第一页的位置信息
      const pageHeight = this.$refs.contenxtPage.getBoundingClientRect();
      // 处理每一页分割位置
      let pageInfo = [];
      for (let i = 0; i < this.pageSum + 1; i++) {
        pageInfo.push(Math.ceil(pageHeight.bottom + this.height * i));
      }
      pageInfo.forEach((item) => {
        for (let i = 0; i < lableListID.length; i++) {
          // 每个元素的bottom位置
          const positionInfo = lableListID[i].getBoundingClientRect();
          const elementBottom = Math.ceil(positionInfo.bottom);
          if (elementBottom > item - 24) {
            // 新div的高度
            const unllHei =
              item -
              24 -
              18 -
              lableListID[i - 1].getBoundingClientRect().bottom;

            this.createEmptyElement(
              lableListID[i],
              unllHei,
              pageHeight,
              lableListID[lableListID.length - 1]
            );
            break;
          }
        }
      });
    },
    //创建空div
    createEmptyElement(currentNode, unllHei, pageHeight, endeNode) {
      // 获取该div的父节点,创建新节点,设置样式
      let divParent = currentNode.parentNode;
      let newNode = document.createElement('div');
      newNode.className = 'emptyDiv';
      newNode.style.height = unllHei + 'px';
      newNode.style.width = '100%';
      newNode.style.marginBottom = 24 + 24 + 18 + 'px';
      newNode.style.overflow = 'hidden';
      newNode.style.paddingLeft = '12px';
      newNode.style.paddingRight = '12px';
      newNode.style.boxSizing = 'borderBox';

      // 将新节点插入到div的下一个兄弟节点之前,即div之后
      divParent.insertBefore(newNode, currentNode);

      // 内容总高
      const content = Math.ceil(
        endeNode.getBoundingClientRect().bottom - pageHeight.bottom
      );
      //需要生成多少空白页
      this.pageSum = Math.ceil(content / this.height);
      /* 执行下载并打印PDF的方法 */
      this.pdfs();
    },


   pdfs() {
      // 避免出现浏览器滚动条导致的内容不全处理
      // document.getElementsByClassName("reportContentBox")[0].scrollTop = 0;
      //div内部滚动导致内容不全处理
      document.getElementById('app').style.height = 'auto';
      setTimeout(() => {
        html2canvas(document.getElementById('reportBox'), {
          background: '#01195e',
          allowTaint: true,
          useCORS: true,
          // height: document.getElementById('upload').scrollHeight,
          // windowHeight: document.getElementById('upload').scrollHeight
        }).then((canvas) => {
          // console.log(canvas);
          // var contentWidth = canvas.width;
          // var contentHeight = canvas.height;
          var contentWidth = parseInt(canvas.style.width) * 2;
          var contentHeight = parseInt(canvas.style.height) * 2;

          // console.log('contentWidth', contentWidth);
          // console.log('contentHeight', contentHeight);
          //一页pdf显示html页面生成的canvas高度;
          var pageHeight = (contentWidth / 592.28) * 841.89;
          //未生成pdf的html页面高度
          var leftHeight = contentHeight;
          //页面偏移
          var position = 0;
          //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
          var imgWidth = 595.28;
          var imgHeight = (592.28 / contentWidth) * contentHeight;
          // console.log('imgHeight', imgHeight);
          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 > 100) {
                pdf.addPage();
              }
            }
          }
        });
      }, 300);
    },
三,效果

 注:因为布局不固定,元素的高各不相同,添加空div会造成大块的空白,需要进一步处理,如果对这块比较在意,可以下载我的代码文

github文件地址 tutoxs/myProject: chuanfangzijidexianxixiangmu (github.com)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值