Vue中使用jspdf的分页,文字截断问题的解决

前两天做了一个在线签订协议的需求,通过弹出框弹出的协议来进行在线签名生成pdf文档,就使用了jsPDF来生成文档,下面来记录一下开发中遇到的问题,及解决的方法。(看我签名。。。)

1.首先要引入对应的npm包(没有下载自行npm i ..... -S下载)

html2Canvas官网: About

jsPdf链接: jsPDF - Documentation

import jsPDF from 'jspdf';
import html2Canvas from 'html2canvas'

2.HTML

<el-dialog>
        <p>北京前端小白科技技术有限公司</p>
        <p>这个人很懒...</p>
        <p>完...</p> 
   </div>
</el-dialog>

3.JS

isSplit (nodes, index, pageHeight) {
                // 计算当前这块dom是否跨越了a4大小,以此分割
                if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {
                    return true;
                return false;
uploadPdf(){
   let ST = document.documentElement.scrollTop || document.body.scrollTop; 
   let SL = document.documentElement.scrollLeft || document.body.scrollLeft;
            document.documentElement.scrollTop = 0;
            document.documentElement.scrollLeft = 0;
            document.body.scrollTop = 0;
            document.body.scrollLeft = 0;
       //获取滚动条的位置并赋值为0,因为是el-dialog弹框,并且内容较多出现了纵向的滚动条,截图出来的效果只能截取到视图窗口显示的部分,超出窗口部分则无法生成。所以先将滚动条置顶
   const A4_WIDTH = 592.28;
   const A4_HEIGHT = 841.89;
   let imageWrapper = document.querySelector(".div") // 获取DOM
   let pageHeight = imageWrapper.scrollWidth / A4_WIDTH * A4_HEIGHT;
   let lableListID = imageWrapper.querySelectorAll("p");
    // 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
        for (let i = 0; i < lableListID.length; i++) {
              let multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight);
                  if (this.isSplit(lableListID, i, multiple * pageHeight)) {
                      let divParent = lableListID[i].parentNode; // 获取该div的父节点
                      let newNode = document.createElement('div');
                          newNode.className = 'emptyDiv';
                          newNode.style.background = '#ffffff';
                      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的下一个兄弟节点
                            // 判断兄弟节点是否存在
                           if (next) {
                              // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
                               divParent.insertBefore(newNode, next);
                           }else{
                              // 不存在则直接添加到最后,appendChild默认添加到divParent的最后
                               divParent.appendChild(newNode);
//接下来开始截图
   this.$nextTick(()=>{
       // nexttick可以保证要截图的部分全部执行完毕,具体用法自行百度...
             html2Canvas(imageWrapper, {
                             allowTaint: true,
                             x: imageWrapper.getBoundingClientRect().left + 13,     // 绘制的dom元素相对于视口的位置
                             y:imageWrapper.getBoundingClientRect().top,        
                             width:imageWrapper.offsetWidth - 15,                   // 因为多出的需要剪裁掉,
                             height:imageWrapper.offsetHeight,
                             backgroundColor:"#FFF", //一定要设置北京颜色,否则有的浏览器就会变花~,比如Edge
                             useCORS: true,
                             scale:3,      // 图片模糊
                             dpi: 350, //z
              }).then((canvas)=>{
                let pdf = new jsPDF('p', 'mm', 'a4');    //A4纸,纵向
                let ctx = canvas.getContext('2d'),
                a4w = 190, a4h = 277,    //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
                imgHeight = Math.floor(a4h * canvas.width / a4w),    //按A4显示比例换算一页图像的像素高度
                renderedHeight = 0;
                while(renderedHeight < canvas.height) {
                    let page = document.createElement("canvas");
                    page.width = canvas.width;
                    page.height = Math.min(imgHeight, canvas.height - renderedHeight);//可能内容不足一页
                   //用getImageData剪裁指定区域,并画到前面创建的canvas对象中
                    page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
                    pdf.addImage(page.toDataURL('image/jpeg', 0.2), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width));    //添加图像到页面,保留10mm边距
                    renderedHeight += imgHeight;
                    if(renderedHeight < canvas.height)
                         pdf.addPage();//如果后面还有内容,添加一个空页
                //     pdf.save('测试.pdf');
                  let uploadPdf =  pdf.output("datauristring") //转成Base64
                   let arr = uploadPdf.split(',')
                   let mime = arr[0].match(/:(.*?);/)[1]
                   let suffix = mime.split('/')[1]
                   let bstr = window.atob(arr[1])  //自行百度新大陆
                   let n = bstr.length
                   let u8arr = new Uint8Array(n)
                   let filename="temp_img";
                   while (n--) {
                         u8arr[n] = bstr.charCodeAt(n)
                   let file =  new File([u8arr], `${filename}.${suffix}`, {type: mime});   
                   let formdata = new FormData();
                   formdata.append("uploadfile",file);
                   let params={project:this.pid,courseid:this.id}
                   this.$axios({
                        url:`vueindex/UploadWord/uploadpdf`,
                        method:"post",
                        headers:{'Content-Type':"multipart/form-data "},
                        data:formdata,
                        params:params        
                    }).then((res)=>{
                        if(res.data.code == 0){
                           //上传成功,刷新页面,打完收工