vue项目html页面生成PDF预览、下载及生成页面水印

html2canvas官方文档
jspdf官方文档

概述

因为生成的PDF内还有富文本,后端不好生成PDF,故由前端完成。

原理

html2canva生成截图,jsPDF利用图片生成PDF。

过程中遇到的问题

1、生成大于30多页时,容易造成生成页面黑屏问题。

  • 原因:canvas生成图片时,对内容高度有一定的限制,超过这个高度,canvas生成不了图片。
  • 解决方案:将html文档中需要生成PDF的部分,不再整个内容生成一张截图,而是根据内容切割成多个具有相同类名的div,生成多张截图。然后循环截图列表,生成PDF。

2、 因为html内容时table包裹的,没有连续一行都是空白的,所以如何判断canvas可以截断

  • 解决方案:遍历循环,如果不是白色的像素点不超过20,可以截断

3、解决了黑屏问题,但是随之,想在一页上添加水印造成了困难。

  • 解决方案:最终生成PDF文件时,遍历每一页PDF,然后将canvas生成的水印于PNG格式,覆盖在每一页PDF上。看了源码才看到jspdf的addImage接口可以传canvas对象,这时候会对图片格式进行确认,然后传PNG格式就可以不覆盖原本的内容了。

生成的PDF截图

页眉、页脚、封面、水印
在这里插入图片描述

代码示例

  • 注意:在本次示例中,因为内容从data中获取,所以在mounted生命周期中调用生成PDF方法。在实际开发中可能是从后台获取的,需要在updated生命周期中调用生成PDF方法。
<template>
  <div class="app-container">
    <div class="mask">
      <div v-if="!isAddPage" class="tips">
        <i class="el-icon-loading"/>
        附件正在生成中......
      </div>
      <div v-else class="tips">
        <i class="el-icon-loading"/>
        附件正在生成第<span class="pdfProgress">{
  { pdfPage }}</span>页,共<span class="pdfTotal">{
  { pdfProgress }}</span>页......
      </div>
    </div>

    <!-- 页眉和页码 -->
    <div class="hideDiv">
      <div id="title">
        <p> 我是页眉 </p>
      </div>
      <div id="footer"><span class="pdfProgress">{
  { pdfPage }}</span></div>
    </div>

    <div id="pdfDom">
      <div id="cover">
        <div class="coverContent">
          <h1 style="font-size: 22px;">XXX股份有限公司</h1>
          <h2 style="font-size: 22px;">《张三报告》</h2>
        </div>
      </div>
      <div class="content">
        <div class="casepoint">
          {
  { pdfContent.content }}
        </div>
        <div class="casepoint">
          {
  { pdfContent.content }}
        </div>
        <div class="casepoint">
          {
  { pdfContent.content }}
        </div>

      </div>
    </div>

  </div>
</template>
<script>
import html2Canvas from 'html2canvas'
import jsPDF from 'jspdf'

export default{
     
  name: 'SeePdf',
  data() {
     
    return {
     
      pdfProgress: 1,
      pdfPage: 1,
      pdfTotal: null,
      type: '01', // 01预览 02下载
      taskno: '',
      pdfContent: {
      content: '我是内容' },
      isDownloaded: false, // 是否生成PDF
      isOver: false, // 是否生成完毕
      a4Width: 595.28,
      a4Height: 841.89,
      pdf: null,
      canvas: [],
      a4HeightRef: 0,
      position: 0,
      leftHeight: 0,
      pageFooter: null,
      canvasFooter: null,
      pageTitle: null,
      canvasTitle: null,
      canvasTitleH: null,
      canvasbreakHeight: 0,
      canvasIndex: 0,
      pageData: null,
      isAddPage: false
    }
  },
  watch: {
     
    isOver: function(newVal) {
     
      if (newVal) {
     
        setTimeout(function() {
     
          window.close()
        }, 300)
      }
    }
  },
  mounted() {
     
    if (!this.isDownloaded) {
     
      this.getPdfFun()
    }
  },
 // 内容从后台接口获取时,在updated生命周期中调用生成PDF方法
  // updated() {
     
  //   if (!this.isDownloaded) {
     
  //     this.getPdfFun()
  //   }
  // },
  methods: {
     
    getPdfFun() {
     
    // 初始化PDF
      this.pdf = new jsPDF('x', 'pt', 'a4')
      this.pdf.page = 1
      this.pdf.setDisplayMode('fullwidth', 'continuous', 'FullScreen')
      this.isDownloaded = true
      if (this.type === '01') {
     
        this.getPdf('pdf名字', true)
      } else if (this.type === '02') {
     
        this.getPdf('pdf名字', false)
      }
    },
    async getPdf(title, show) {
     
      // 生成页眉图片
      this.canvasTitle = await html2Canvas(document.getElementById('title'))
      this.pageTitle = this.canvasTitle.toDataURL('image/jpeg', 1.0)

      // 生成首页图片
      const canvasCover = await html2Canvas(document.querySelector('#cover'), {
     
        allowTaint: true,
        scale: 2
      })

      // 生成首页PDF
      this.pdf.addImage(canvasCover.toDataURL('image/jpeg', 1.0), 'JPEG', 0, 0, this.a4Width, this.a4Width / canvasCover.width * canvasCover.height)

      // 生成内容 6个案件点的图片
      const doms = document.getElementsByClassName('casepoint')
      for (let i = 0
  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值