前端vue实现导出pdf文件报告组件

大屏项目有一个需求,需要对展示的内容进行文件导出,但是目前后台没有相关的逻辑,所以只能前端硬上,在参考了其他许多的逻辑之后,目前我自己这边做了一套比较笨的组件,通过拼接标签这种方法来实现对你想需要的地方进行文件导出,并且呈现出比较让人接受的样式,下面以一个实例来介绍。

需求模拟:

目前有一个大屏项目
在这里插入图片描述

客户在点击导出分析报告的时候能够得到下面这种样式的pdf文件(只能是pdf,word,jpg什么的都不行),并且需要有预览界面

demo生成的pdf文件展示:

在这里插入图片描述
在这里插入图片描述

讲一下技术手段吧,主要用到的还是这俩大熟人

html2canvas
jspdf

首先是根据对界面的提取,获得canvas生成的图片,然后附着在一个pdf上,最后保存下载。这一部分的代码可以说是直接照搬的别人的:

/*
 * @Author: 你的名字
 * @Date: 2023-03-16 11:05:59
 * @FilePath: /demo-gather/src/lib/pdf.js
 * @Description: 
 */

import html2canvas from "html2canvas";
import jsPDF from "jspdf";

export const downloadPDF = async (page,title) => {
  // let modules = [page];
  let modules = page

  if (!modules.length) return;
  const a4Width = 595.28
  const a4Height = 841.89
  const pdf = new jsPDF('p', 'pt')
  // 生成所有pdf页
  async function setPdfPage() {
    for (let i = 0; i < modules.length; i++) {
      const item = modules[i]
      const canvas = await html2canvas(item)
      const contentWidth = canvas.width
      const contentHeight = canvas.height
      const pageData = canvas.toDataURL('image/jpeg', 1) // 第二个参数为图片质量,1为最高质量
      let imgHeight = (a4Width / contentWidth) * contentHeight // 根据a4纸比例,计算出图片的高度
      const marginY = (a4Height - imgHeight) / 2 // 计算出图片的上下边距
      // 第三个参数图片x轴位置,第四个参数图片y轴位置,第五个参数图片宽度,第六个参数图片高度
      pdf.addImage(pageData, 'JPEG', 0, marginY > 0 ? 0 : 0, a4Width, imgHeight > a4Height ? imgHeight : imgHeight)
      // 最后一个模块不需要再新增空白页
      if (i < modules.length - 1) {
        pdf.addPage()
      }
    }
  }
  await setPdfPage()
  pdf.save(title+".pdf") // 导出pdf
  // 还原元素
  // html2canvas(page).then(function(canvas) {
  //   canvas2PDF(canvas,title);
  // });
};


export  const canvas2PDF = (canvas,title) => {
  let contentWidth = canvas.width;
  let contentHeight = canvas.height;

  //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  let imgWidth = 595.28;
  let imgHeight = 592.28/contentWidth * contentHeight;
if(imgHeight>841){
    imgHeight = 841;
    imgWidth = 841/contentHeight * contentWidth;
}
  // 第一个参数: l:横向  p:纵向
  // 第二个参数:测量单位("pt","mm", "cm", "m", "in" or "px")
  let pdf = new jsPDF("p", "pt");

  pdf.addImage(
    canvas.toDataURL("image/jpeg", 0.9),
    "JPEG",
    0,
    0,
    imgWidth,
    imgHeight
  );

  pdf.save(title+".pdf");
};

这里主要介绍一下这个预览界面我的实现方法,目前适配了这些情况:
一般采用ref拿到元素下面的html内容,克隆在弹出框的内容中,组件接收到一个fileList数组,每一项代表克隆的显示内容, 每一项的展示示例:

title:当前内容的标题
src:组件渲染的主要内容
type:当前需要渲染的内容的类型(包括:不定义的类型(‘’),echarts,table)
不定义类型的话采用vhtml绑定src直接展示出来,

echarts类型需要联动我之前做的echarts展示组件来使用,拿到整个option给src,导出预览的组件里面会有一个chart-com组件接收options配置项;

table类型需要将表头的配置项一个表格数据一并传给预览组件,具体实例参考我的demo项目代码。

   initFileSrc(domList) {
      let _this = this;
      let src = "";
      // this.dynamicDom = "";
      for (let item of domList) {
        if (item.isComponent) {
          src = _this.$refs[item.name].$el.outerHTML;
        } else {
          src = _this.$refs[item.name].outerHTML;
        }
        _this.fileList.push({ title: item.title ? item.title : "", src: src });
      }
    },

组件应用当中遇到的问题:
1.分页如何处理
2.如果有子标签怎么处理

demo项目代码地址
https://gitee.com/mrzaco/demo-gather/blob/main/src/views/ChartTest/ChartTest.vue

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值