vue将页面导出pdf,vue导出pdf ,使用html2canvas和jspdf组件

发布于:2025-06-28 ⋅ 阅读:(22) ⋅ 点赞:(0)

vue导出pdf

需求:需要前端下载把当前html下载成pdf文件–有十八页超长,之前使用vue-html2pdf组件,但是这个组件有长度限制和比较新浏览器版本限制,所以改成使用html2canvas和jspdf组件
方法:
1、第一步:我们要添加两个模块

//第一个:将页面html转换成图片
npm install --save html2canvas
//第二个:将图片生成pdf
npm install jspdf --save

2、第二步:在.vue界面编写,例如我的页面叫BusinessAnalysis.vue,必须在你想要下载的父级加一个id,例如我下面代码 id=“html2PdfId”

<template>
<div ref="ananysisPageRef" class="business-analysis-wrap" >
    <div  id="html2PdfId">
   //=====这里是你自己写的想转成pdf的代码
    </div>
   <a-button
    type="primary"
    :loading="exportLoading"
     @click="handleExportAI2()"
     >
   导出PDF
 </a-button>
</div>
</template>
<script>
import VueHtml2pdf from 'vue-html2pdf'
import html2canvas from 'html2canvas'
export default {
name: 'BusinessAnalysis',
data() {
 return {
 pdfOptions: {
     pageWidth: 594, // A2横向宽度(mm)
     pageHeight: 420, // A2横向高度(mm)
     imageQuality: 0.8,
   },
   exportLoading: false,
   pdfBase64: '',
   base64Images: [],
    }
  }
  methods: {
      handleExportAI2() {
       this.$message.loading({ content: '导出PDF文件中...', key: 'exportPagePdfLoading' })
       this.exportLoading = true
       this.generatePDF() // 生产pdf base64 --物业经营分析2
      },
       async generatePDF() {
       const startTime = performance.now()

 	      try {
 	        await this.$nextTick()
 	        // 1. 定义要截图的元素ID(按顺序)
 	        // 2. 截图所有元素并计算高度
 	        const elements = await this.captureComponents1()
 	        console.log('elements', elements)
 	        const img = await this.loadImage(elements[0])
 	
 	        // this.restoreAfterCapture();
 	        // 3. 创建PDF并智能分页
 	
 	        const pdf = new JsPDF({
 	          orientation: 'l',
 	          unit: 'mm',
 	          format: [this.pdfOptions.pageWidth, this.pdfOptions.pageHeight],
 	          // format: 'a4',
 	          // compress: true
 	        })
 	        // 计算分页参数:ml-citation{ref="6,8" data="citationList"}
 	        const imgRatio = img.width / img.height
 	        const scaledWidth = this.pdfOptions.pageWidth
 	        const scaledHeight = scaledWidth / imgRatio
 	        const totalPages = Math.ceil(scaledHeight / this.pdfOptions.pageHeight)
 	
 	        // 分页渲染:ml-citation{ref="5,8" data="citationList"}
 	        for (let i = 0; i < totalPages; i++) {
 	          if (i > 0) pdf.addPage()
 	
 	          const canvas = document.createElement('canvas')
 	          const ctx = canvas.getContext('2d')
 	
 	          // 计算截取区域:ml-citation{ref="6,8" data="citationList"}
 	          const sliceHeight = (img.height * this.pdfOptions.pageHeight) / scaledHeight
 	          const startY = i * sliceHeight
 	          const isLastPage = i === totalPages - 1
 	          const currentSliceHeight = isLastPage ? img.height - startY : sliceHeight
 	
 	          // 设置画布尺寸:ml-citation{ref="3,5" data="citationList"}
 	          canvas.width = img.width
 	          canvas.height = currentSliceHeight
 	
 	          // 绘制图片分段:ml-citation{ref="5,6" data="citationList"}
 	          ctx.drawImage(
 	            img,
 	            0,
 	            startY, // 源坐标
 	            img.width,
 	            currentSliceHeight, // 源尺寸
 	            0,
 	            0, // 目标坐标
 	            canvas.width,
 	            canvas.height // 目标尺寸
 	          )
 	
 	          // 计算PDF中的显示高度:ml-citation{ref="6,8" data="citationList"}
 	          const displayHeight = isLastPage
 	            ? (currentSliceHeight * this.pdfOptions.pageWidth) / img.width
 	            : this.pdfOptions.pageHeight
 	
 	          pdf.addImage(canvas, 'JPEG', 0, 0, this.pdfOptions.pageWidth, displayHeight, undefined, 'FAST')
 	
 	          canvas.width = 1
 	          canvas.height = 1
 	        }
 	        this.exportLoading = false
 	        this.$message.success({ content: '导出成功!', key: 'exportPagePdfLoading', duration: 1 })
 	        pdf.save('物业经营小项目分享.pdf')
 	      } catch (error) {
 	        console.error('生成PDF失败:', error)
 	        alert('生成PDF失败: ' + error.message)
 	      } finally {
 	        this.isGenerating = false
 	      }
 	    },
 	    loadImage(base64) {
 	      return new Promise((resolve, reject) => {
 	        const img = new Image()
 	        img.onload = () => resolve(img)
 	        img.onerror = reject
 	        img.src = base64
 	      })
      },
      async captureComponents1() {
 	      // 确保DOM更新完成(针对Vue的动态渲染)
 	      await this.$nextTick()
 	      const elements = [document.getElementById('html2PdfId')]
 	
 	      const base64Images = []
 	
 	      // 顺序截图(避免并行导致内存溢出)
 	      for (const element of elements) {
 	        // 分块截图
 	        try {
 	          const canvas = await html2canvas(element, {
 	            useCORS: true, // 允许跨域资源
 	            logging: false, // 关闭日志
 	            backgroundColor: '#FFFFFF', // 设置纯白背景
 	            scale: 2, // 提高分辨率(2倍)
 	            allowTaint: true, // 禁止污染画布
 	            removeContainer: true, // 自动移除临时容器
 	            windowWidth: element.scrollWidth,
 	            windowHeight: element.scrollHeight,
 	            // ignoreElements: (el) => {
 	            //   // 过滤不需要渲染的元素
 	            //   if (
 	            //     el.contains(element) ||
 	            //     element.contains(el) ||
 	            //     el.tagName === 'STYLE' ||
 	            //     el.tagName === 'LINK' ||
 	            //     // el.tagName === 'IMG' ||
 	            //     el.getAttribute('data-html2canvas') != null // header里面的样式不能筛掉
 	            //   ) {
 	            //     // console.log(el);
 	            //     return false
 	            //   }
 	            //   // console.log(e.tagName);
 	            //   return true
 	            // },
 	            // dpi: 300
 	          })
 	
 	          const dataUrl = canvas.toDataURL('image/png', 1.0)
 	          base64Images.push(dataUrl)
 	        } catch (error) {
 	          console.error('截图失败:', element, error)
 	          base64Images.push('') // 空值占位
 	        }
 	      }
 	      return base64Images
 	    },
  }
}
</script>

上面基本上是完整的代码,花了九头二虎之力,就是还是会出现截断的情况,我没办法解决,如果有大佬,求大佬指导
在这里插入图片描述
可以下载22页呢,就是下载的时候先截图成图片,再转为pdf很慢,如果有大佬能解决很慢的问题,求指导


网站公告

今日签到

点亮在社区的每一天
去签到