前端-如何将前端页面输出为PDF并打包的压缩包中

需要引入的依赖:

javascript 复制代码
import * as utils from '../../utils/utils'
import html2canvas from "html2canvas";
import JSZip from "jszip";
import JSPDF from "jspdf";
import FileSaver from "file-saver"

import { Loading } from "element-ui";
javascript 复制代码
importDetailPdf(title) {
      // 显示加载提示(告知用户正在生成导出 PDF)
      this.showLoading("正在处理数据,请等待...")
      let that = this
      // 需要导出为 PDF 的 DOM 容器(整页内容区域)
      var element = document.getElementById("pdfDom")
      // 将 DOM 渲染为画布(canvas)
      html2canvas(element, {
        logging: false // 关闭调试日志,减少控制台输出
      }).then(function (canvas) {

        // 创建 A4 纵向 PDF 文档:单位 mm,纸张 a4
        var pdf = new JSPDF("p", "mm", "a4") // A4纸,纵向

        // 画布上下文
        var ctx = canvas.getContext("2d")
        // A4 内容显示区域:210 x 297(mm),预留四周 20mm 边距 => 内容 170 x 257(mm)
        var a4w = 170;
        var a4h = 257 // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257
        // 计算一页可容纳的图像像素高度(按 A4 内容区域等比换算)
        var imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
        // 已经渲染(导出)的高度累计
        var renderedHeight = 0

        // 循环切割整张长画布,分页写入 PDF
        while (renderedHeight < canvas.height) {
          // 针对当前页创建一个临时画布,宽度与原始画布一致,高度为"单页可显示高度"或剩余高度
          var page = document.createElement("canvas")
          page.width = canvas.width
          page.height = Math.min(imgHeight, canvas.height - renderedHeight)// 可能内容不足一页

          // 从原始画布中截取当前页区域像素并绘制到临时画布
          page.getContext("2d").putImageData(
              ctx.getImageData(
                  0, renderedHeight,               // 起始坐标
                  canvas.width,                    // 截取宽度
                  Math.min(imgHeight, canvas.height - renderedHeight) // 截取高度
              ),
              0, 0
          )

          // 将当前页画布作为图片添加到 PDF:
          // 位置 (10,10) mm(四周 10mm 边距),宽度 a4w,高度按比例缩放(不超过 a4h)
          pdf.addImage(
              page.toDataURL("image/jpeg", 1.0), // 图片数据,JPEG,质量 1.0
              "JPEG",
              10, 10,                             // PDF 内左上角定位(mm)
              a4w,                                // 显示宽度(mm)
              Math.min(a4h, a4w * page.height / page.width) // 按比例计算的显示高度(mm)
          )

          // 递增已渲染高度
          renderedHeight += imgHeight
          // 如果还有未导出的内容,则在 PDF 中新增一页
          if (renderedHeight < canvas.height) {
            pdf.addPage()
          }// 如果后面还有内容,添加一个空页
          // delete page; // 如需主动释放可在合适场景处理
        }

        // 未传入标题时,采用当前时间作为标题(注意:此处 this 作用域为 then 回调,不是 Vue 实例)
        if (title == undefined) {
          title = this.nowTimeDesc()
        }

        // 输出 PDF 为 dataURL 字符串
        let datauri = pdf.output('dataurlstring')
        // 截取 base64 数据体(去掉前缀 data:application/pdf;base64, => 28 字符)
        let base64 = datauri.substring(28)

        // 将 PDF 打包进 zip
        let zip = new JSZip()
        let fileName = title + ".pdf"
        zip.file(fileName, base64, {base64: true})

        // 如果有其他需要一并下载的附件,这里继续打包后统一下载
        that.downloadOtherFile(zip, title)
      })
    },
    downloadOtherFile(zip, title) {
      this.showLoading("正在打包文档,请等待...")
      //查找所有的文档
      // zip.generateAsync({type:"blob"}).then(content => {
      //   FileSaver.saveAs(content,title + ".zip")
      // })
      // return
      let list = this.allProjectFileList
      if (utils.isEmpty(list) || list.length == 0) {
        //没有要下载的文档,直接打包并保存成文件
        zip.generateAsync({ type: "blob" }).then(content => {
          FileSaver.saveAs(content, title + ".zip")
        }).finally(() => {
          this.endLoading()
        })
        return
      }
      let promises = []
      list.forEach(item => {
        let promise = this.downloadProFile(item).then((res, file) => {
          file
          zip.file(this.parseFileType(item) + item.archiveName, res.data, { binary: true })
        })
        promises.push(promise)
      })
      Promise.all(promises).then(() => {
        zip.generateAsync({ type: "blob" }).then(content => {
          FileSaver.saveAs(content, title + ".zip")
        }).finally(() => {
          this.endLoading()
        })
      })
    },
    endLoading() {
      this.$nextTick(() => {
        if (this.loading) {
          this.loading.close()
        }
      })
    },

如果需要对页面中的内容进行判断,手动选择pdf中的内容则:

对页面中的内容使用v-if来进行逻辑渲染,根据逻辑判断此时是否是导出pdf。

javascript 复制代码
showProjectTeam() {
      if (!this.isExport) {
        return true
      }
      return this.projectTeam
    },