前端导出 pdf 并且压缩 zip

需求

1、前端自定义 html 模板,导出 pdf
2、多个 pdf 导出压缩到一个文件 zip 里面

原理

1、html2Canvas 将 html 模板转为 canvas
2、canvas 转为 img 图片
3、生成的图片添加到 pdf 里面

用到的插件

html2canvas
jspdf
jszip
file-saver

模板



异步导出函数

async exportMeeting (type) {
      // type:'1' 选择导出 'all':导出所有
      try {
        this.allLoading = true
        let selectedData = []
        if (type === '1') {
          const ids = this.multipleSelection.map(el => el.id)
          selectedData = await this.getMeetingAll(ids)
        } else if (type === 'all') {
          selectedData = await this.getMeetingAll()
        }
        this.loadingText = '正在拼命导出...'

        const zip = new JSZip()
        const promises = []
        this.isShowPdf = true

        for (let i = 0; i < selectedData.length; i++) {
          const element = selectedData[i]
          this.data = element
          // 等待每一个转为pdf
          const p = await htmlToPdf.getPdf(document.getElementById('pdf'), element.meetingName)
          promises.push(p)
        }
        // 等到所有的promise执行完成依次压缩到zip中
        Promise.all(promises).then(async (pdfs) => {
          for (let i = 0; i < pdfs.length; i++) {
            const { PDF, name } = pdfs[i]
            // 如果只是导出一个pdf,则导出pdf格式
            if (pdfs.length === 1) {
              PDF.save(`${name}-${new Date().getTime()}.pdf`)
              this.allLoading = false
              this.loadingText = '正在请求数据'
            } else {
              // 否则添加到压缩包里面
              await zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob'))
            }
          }
          if (pdfs.length > 1) {
            zip.generateAsync({ type: 'blob' }).then(content => {
              FileSaver.saveAs(content, '销项管理平台会议纪要.zip')
            })
          }
        }).finally(() => {
          this.allLoading = false
          this.loadingText = '正在请求数据'
        })
      } catch (e) {
        this.allLoading = false
        this.loadingText = '正在请求数据'
        throw new Error(e)
      }
    },

获取 pdf 的公共封装函数

// 导出pdf
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';

export default {
  getPdf: (el, pdfName) => {
    // 滚轮滑动造成的,主要是html2canvas是根据body进行截图,若内容高度高于body时,就会出现这样的问题
    // 解决方案:(在生成截图前,先把滚动条置顶)
    window.pageYoffset = 0;
    document.documentElement.scrollTop = 0;
    document.body.scrollTop = 0;

    return new Promise((resolve, reject) => {
      // 在点击保存图片时,此时要保存的资源较多,造成模块并没有完全加载完毕,就已经生成了截图。
      // 解决方案:(延迟)
      setTimeout(() => {
        // 这句挺重要
        html2Canvas(el, {
          scale: 4,
          dpi: 300,
          useCORS: true,
          // allowTaint: true
        })
          .then((canvas) => {
            const contentWidth = canvas.width;
            const contentHeight = canvas.height;
            const pageHeight = (contentWidth / 592.28) * 841.89;
            let leftHeight = contentHeight; //
            let position = 0;
            const imgWidth = 595.28;
            const imgHeight = (592.28 / contentWidth) * contentHeight;
            const pageData = canvas.toDataURL('image/jpeg', 1.0);
            const PDF = new JsPDF('', 'pt', 'a4');
            if (leftHeight < pageHeight) {
              // 在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
              PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
              // pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);
            } else {
              // 分页
              while (leftHeight > 0) {
                PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
                leftHeight -= pageHeight;
                position -= 841.89;
                // 避免添加空白页
                if (leftHeight > 0) {
                  PDF.addPage();
                }
              }
            }
            resolve({ PDF, name: pdfName });
          })
          .catch((e) => {
            reject(e);
          });
      }, 500);
    });
  },
};

遇到的问题

  • 添加到 zip 时,获取 pdf 的内容
zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //第二个参数PDF.output('blob')
  • 添加到 zip 时,同名文件会被覆盖
// 通过给文件名添加一个时间戳解决
zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //`${name}-${new Date().getTime()}.pdf`

你可能感兴趣的:(前端导出 pdf 并且压缩 zip)