前端vue的JsPDF html2canvas 生成pdf并以文件流形式上传到后端,vue导出pdf以及过程中滚动条外内容无法获取的问题

1.首先在文件内引入htmlToPdf.js
这里代码引入了html2canvas和jspdf
//需要 npm i html2Canvas 和 npm i jspdf

在这里将getPdf 这个函数挂载到Vue的原型上,最后return一个promise对象(包含了resolve的base64Pdf,以便于处理),在局部组件内可进行.then以进行上传后端等操作。
插件代码如下

import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
  install(Vue, options) {
    /**
     * 
     * @param {*} reportName 下载时候的标题
     * @param {*} isDownload  是否下载默认为下载,传false不下载
     */
    Vue.prototype.getPdf = function (reportName, isDownload = true) {
      //     var target = document.getElementsByClassName("right-aside")[0];
      // target.style.background = "#FFFFFF";
      return new Promise((resolve, reject) => {
        var title = reportName;
        html2Canvas(document.querySelector('#pdfDom'), {
          allowTaint: true
        }).then((canvas) => {
          let contentWidth = canvas.width
          let contentHeight = canvas.height
          //一页pdf显示html页面生成的canvas高度;
          let pageHeight = contentWidth / 592.28 * 841.89
          //未生成pdf的html页面高度
          let leftHeight = contentHeight
          //页面偏移
          let position = 0
          //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
          let imgWidth = 595.28
          let imgHeight = 592.28 / contentWidth * contentHeight
          let pageData = canvas.toDataURL('image/jpeg', 1.0)
          let 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()
              }
            }
          }
          if (isDownload) {
            PDF.save(title + '.pdf')
          }
          // 删除本地存储的base64字段
          var pdfData = PDF.output('datauristring')//获取base64Pdf
          resolve(pdfData)
        }
        )
      })
    }
  }
}

import htmlToPdf from '@/utils/htmlToPdf.js'
Vue.use(htmlToPdf)
              <div   
                 style="
                  height: 69vh;
                  overflow-y: auto;
                  font-size: 16px;
                  padding: 10px 10px;
               ">
                <div id="pdfDom">//为需要导出的DOM添加id
                      <div    v-for="(item,index) in dataText2" :key="index" >
                          <div
                            style="white-space: pre-wrap; width: 100%; height: 100%"
                            v-html="item"
                          >
                          </div>
                      </div>
                </div>
              </div>



                 <el-button
                  type="success"
                  @click="toGetPdf()"//触发事件
                  style="width: 150px; background: #409eff;margin-left:100px"
                >
                  导出内容为PDF
                </el-button>
//如果不需要上传直接导出到这一步就可以了,只需要将download = true即可导出
    toGetPdf(tile = "", download = false) {
      this.getPdf(tile, download) //download:false为不下载,这里调用了刚刚引用的全局函数,.then得到的值是base64位的pdf文件
        .then((res) => {
          this.UploadPdf(res);
        });
    },
//如果需要上传到后台
   UploadPdf(res) {
      //res拿到base64的pdf
      let pdfBase64Str = res;
      let title = "上传给后端的个人报告";
      var myfile = this.dataURLtoFile(pdfBase64Str, title + ".pdf"); //调用一下下面的转文件流函数
      //let fd = new FormData(); ///忽略这边的我个人的上传请求,我这边是将jspdf生成的单层PDF,交给后台变为双层的
      //fd.append("files", myfile);
      //fd.append("serverFilePath", path);
      //this.$http({
        //url:
          //window.SITE_CONFIG["orcUrl1"] +
          //"/rest/file/small/nr/upload/files_pdf",
       // method: "post",
       // data: fd,
       // rest: true,
       // isFormData: true,
      }).then((res) => {//这边是后台返回了base64的格式,所以我要转为blob
        const blob = this.base64ToBlob(res.data);
        const elink = document.createElement("a");
        // const fname = item.name + str + "_" + lists[1] + lists[2]; // 下载文件的名字
        const fname = "pdf"; // 下载文件的名字
        elink.download = fname;
        elink.style.display = "none";
        elink.href = URL.createObjectURL(blob);
        document.body.appendChild(elink);
        elink.click();
        URL.revokeObjectURL(elink.href); // 释放URL 对象
        document.body.removeChild(elink);
        // if (window.navigator && window.navigator.msSaveOrOpenBlob) {//这个是跳转新窗口直接打开
        //   window.navigator.msSaveOrOpenBlob(blob);
        // } else {
        //   const fileURL = URL.createObjectURL(blob);
        //   window.open(fileURL);
        // }
      });
    },
    base64ToBlob(code) {//base64转二进制流(blob)
      code = code.replace(/[\n\r]/g, "");
      const raw = window.atob(code);
      const rawLength = raw.length;
      const uInt8Array = new Uint8Array(rawLength);
      for (let i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
      }
      return new Blob([uInt8Array], { type: "application/pdf" });
    },
    /*
将base64转换为文件,接收2个参数,第一是base64,第二个是文件名字
最后返回文件对象
*/
    dataURLtoFile(dataurl, filename) {
      var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, { type: mime });
    },

vue导出pdf以及过程中滚动条内容无法获取的问题,可视区外的读取不了,导致生成的PDF不全
在这里插入图片描述
在导出时,有时候会出现导出内容有滚动条的话导出内容不全,只能导出可视部分,滚动条隐藏掉的内容不会展示出来,这个问题我也看了很多的文档,发现都没有什么好的方法可以解决,所以我的解决方法就是:把含有滚动条的内容放在页面外部,

              <div   
                 style="
                  height: 69vh;
                  overflow-y: auto;
                  font-size: 16px;
                  padding: 10px 10px;
              ">
                <div id="pdfDom">//将id放在被读取的内容外面,
                                // 简单来说就是用pdfDom把出现滚动条的内容包裹起来
                      <div    v-for="(item,index) in dataText2" :key="index" >
                          <div
                            style="white-space: pre-wrap; width: 100%; height: 100%"
                            v-html="item"
                          >
                          </div>
                       </div>
                </div>
              </div>

打印实现

//打印功能,dataResult是后台返回的base64
let blob = this.dataURLtoBlob(dataResult);
var date = (new Date()).getTime()
var ifr = document.createElement('iframe')
ifr.style.frameborder = 'no'
ifr.style.display = 'none'
ifr.style.pageBreakBefore = 'always'
ifr.setAttribute('id', 'printPdf' + date)
ifr.setAttribute('name', 'printPdf' + date)
ifr.src = window.URL.createObjectURL(blob)
document.body.appendChild(ifr)
this.doPrint('printPdf' + date)
window.URL.revokeObjectURL(ifr.src) // 释放URL 对象

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值