使用jspdf将html页面生成pdf文件

1、下载jspdf插件包

npm i jspdf

2、在utils文件夹下创建一个单独的文件(名字无具体要求)

// 页面导出为pdf格式,title表示为下载的标题,html表示要下载的页面
import html2Canvas from 'html2canvas' // 不用单独去下载这个包,下载jspdf包时就已经下载下来了,所以直接用就可以了
import JsPDF from 'jspdf'
import { Loading } from 'element-ui'
let noTableHeight = 0; //table外的元素高度
function htmlPdf(title, html, lableList, type) {// type传有效值pdf则为横版const loading = Loading.service({lock: true,text: '正在生成PDF文件',spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'})if (lableList) {const pageHeight = Math.floor(277 * html.scrollWidth / 190); //计算pdf高度for (let i = 0; i < lableList.length; i++) { //循环获取的元素const multiple = Math.ceil((lableList[i].offsetTop + lableList[i].offsetHeight) / pageHeight); //元素的高度if (isSplit(lableList, i, multiple * pageHeight)) { //计算是否超出一页let _H = '' //向pdf插入空白块的内容高度_H = multiple * pageHeight - (lableList[i].offsetTop + lableList[i].offsetHeight);let newNode =  getFooterElement(_H);  //向pdf插入空白块的内容const divParent = lableList[i].parentNode; // 获取该div的父节点const next = lableList[i].nextSibling; // 获取div的下一个兄弟节点// 判断兄弟节点是否存在if (next) {// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后divParent.insertBefore(newNode, next);} else {// 否则向节点添加最后一个子节点divParent.appendChild(newNode);}}}}html2Canvas(html, {allowTaint: false,taintTest: false,logging: false,useCORS: true,dpi: window.devicePixelRatio * 1, scale: 4 // 按比例增加分辨率,图片模糊时数值调高点}).then(canvas => {let pdf = new JsPDF('p', 'mm', 'a4'); // A4纸,纵向let ctx = canvas.getContext('2d');let a4w = type ? 277 : 190; let a4h = type ? 190 : 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277let imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度let renderedHeight = 0;while (renderedHeight < canvas.height) {let page = document.createElement('canvas');page.width = canvas.width;page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距renderedHeight += imgHeight;if (renderedHeight < canvas.height) {pdf.addPage();// 如果后面还有内容,添加一个空页}// delete page;}loading.close()// 保存文件pdf.save(title + '.pdf');});
}// pdf截断需要一个空白位置来补充
function getFooterElement(remainingHeight, fillingHeight = 0) {const newNode = document.createElement('div');newNode.style.background = '#ffffff';newNode.style.width = 'calc(100% + 8px)';newNode.style.marginLeft = '0px';newNode.style.marginBottom = '0px';newNode.classList.add('divRemove');newNode.style.height = (remainingHeight + fillingHeight) + 'px'; return newNode;
}
// 计算是否超出一页
function isSplit(nodes, index, pageHeight) {noTableHeight+= nodes[index].clientHeightreturn nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight  > pageHeight;
}
export default htmlPdf;
<el-button type="primary" @click="exportReport">输出报表</el-button>
<div class="output-report-pdf" ref="outputReportPDF" v-if="outputReportPDFShow"><div class="pdf-item" ref="outputReportPDFItem" v-for="(item, index) in reportPdfData" :key="index" :style="(index + 1) % 2 !== 0 ? 'border-bottom: none': ''"><div class="output-report-img"><el-image style="width: 100%; height: 100%" :src="item.img" fit="contain" @load="handleImage(index)"></el-image></div></div>
</div><script>
// 引入刚才创建的文件
import htmlPdf from '@/utils/htmlToPdf'data() {return {outputReportPDFShow: false}
},
methods: {exportReport() {this.reportPdfData = '从后端获取到的数据'this.outputReportPDFShow = true},// el-image加在完图片时触发handleImage(index) {// 等最后一张图片在页面中加在完再输出成pdf,要不然pdf文件里的图片会不显示if (index + 1 === this.reportPdfData.length) {const name = '测试'// name:保存的文件名称;this.$refs.outputReportPDF:要输出成pdf的总模块;this.$refs.outputReportPDFItem:总模块中的每个item,用于判断是否需要在换页时加个空白框隔开htmlPdf(name, this.$refs.outputReportPDF, this.$refs.outputReportPDFItem)this.outputReportPDFShow = false}}
}
</script><style scoped lang="scss">
.output-report-pdf {.pdf-item {// 其它样式根据具体要求设置,但是每个小模块的宽高有要求,因为要计算小模块是否需要放到下一页显示width: 570px; // pdf的高度:277 * width / 190, width最好是190的倍数;出现小数时容易出错height: 415px; // 高度最好不要超过一页pdf的高度border: 1px solid #000000;.output-report-img {width: 100%;height: 100%;}}           
}
</style>

每页pdf的高度计算公式
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/848835.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot的自动配置是什么?

Spring Boot 的自动配置是指 Spring Boot 能够根据类路径中的jar依赖、定义的bean以及各种属性设置&#xff0c;自动配置应用的过程。 自动配置的目标是减少开发者在开始一个新项目或者给现有项目添加新特性时的工作量&#xff0c;同时避免需要使用大量的配置。Spring Boot 通…

【Mybatis】动态SQL标签2

choose (when, otherwise)标签是使用举例 类似switch...case&#xff0c;从上到下匹配&#xff0c;找到匹配的条件&#xff0c;就结束匹配其他的&#xff01; set标签是使用举例 set这个标签是用在更新操作上的 set标签代替sql中的set关键字&#xff0c;可以把set语句后多余的…

大模型产品层出不穷,如何慧眼识珠?

先预祝亲爱的读者们“端午安康“ 大模型百花齐放&#xff0c;选择难上加难 面对眼前层出不穷的大模型产品&#xff0c;许多人会不禁感到困惑&#xff1a;哪个才是真正适合自己的爆款大模型?在中国本土 alone&#xff0c;就有百来个大模型产品&#xff0c;简直是五花八门&…

基于openssl实现AES ECB加解密

AES加密&#xff0c;全称高级加密标准&#xff08;Advanced Encryption Standard&#xff09;&#xff0c;是一种广泛使用的对称加密算法&#xff0c;用于保护电子数据的安全。以下是AES加密的基本原理和特点&#xff1a; 基本概念 对称加密&#xff1a;AES是一种对称加密算法…

Opengrok代码在线查看平台

OpenGrok 是一个基于 Web 的源代码搜索引擎和交叉引用工具&#xff0c;它可以用来浏览和搜索代码库。虽然 OpenGrok 提供了代码搜索、查看文件和历史等功能&#xff0c;但它本身不是一个完整的在线集成开发环境&#xff08;IDE&#xff09;。然而&#xff0c;OpenGrok 可以作为…

网络科技时代的崛起:十个网站链接深度解读

在当下这个信息化、网络化飞速发展的时代&#xff0c;网络科技已经渗透到我们生活的方方面面。从信息传递、教育培训&#xff0c;到企业管理、城市生活&#xff0c;网络科技以其独特的魅力和无限的可能性&#xff0c;正在引领我们进入一个全新的世界。今天&#xff0c;我们就通…

python怎么下载numpy

安装Python step1&#xff1a;官网下载安装包&#xff1b; https://www.python.org/ 我下载的是python-3.4.4.msi step2&#xff1a;python环境变量配置&#xff1b; 计算机-属性-高级系统设置-环境变量-系统变量 找到PATH&#xff0c;点击编辑&#xff0c;加英文分号;在…

【Text2SQL 论文】T5-SR:使用 T5 生成中间表示来得到 SQL

论文&#xff1a;T5-SR: A Unified Seq-to-Seq Decoding Strategy for Semantic Parsing ⭐⭐⭐ 北大 & 中科大&#xff0c;arXiv:2306.08368 文章目录 一、论文速读二、中间表示&#xff1a;SSQL三、Score Re-estimator四、总结 一、论文速读 本文设计了一个 NL 和 SQL 的…

【设计模式深度剖析】【3】【行为型】【职责链模式】| 以购物中心客户服务流程为例加深理解

&#x1f448;️上一篇:命令模式 设计模式-专栏&#x1f448;️ 文章目录 职责链模式定义英文原话直译如何理解呢&#xff1f; 职责链模式的角色1. Handler&#xff08;抽象处理者&#xff09;2. ConcreteHandler&#xff08;具体处理者&#xff09;3. Client&#xff08;客户…

PostgreSQL 17新特性之分区拆分与合并

PostgreSQL 17 增强了分区管理功能&#xff0c;支持分区的拆分以及合并&#xff0c;同时支持分区表的标识列以及排除约束功能。 本文给大家介绍一下新增的分区拆分&#xff08;ALTER TABLE … SPLIT PARTITION …&#xff09;和分区合并&#xff08;ALTER TABLE … MERGE PART…

【Vue】普通组件的注册使用-局部注册

文章目录 一、组件注册的两种方式二、使用步骤三、练习 一、组件注册的两种方式 局部注册&#xff1a;只能在注册的组件内使用 ① 创建 .vue 文件 (三个组成部分) 以.vue结尾的组件&#xff0c;一般也叫做 单文件组件&#xff0c;即一个组件就是组件里的全部内容 ② 在使用的组…

分享一款提取抖音小店商家电话的软件使用教程

抖音作为一款国内非常流行的短视频分享平台&#xff0c;吸引了大量用户和商家。许多商家在抖音上开设了小店&#xff0c;但是抖音并没有提供直接获取商家电话的功能。本文将分享一款提取抖音小店商家电话的软件&#xff0c;并附带使用教程和代码。 教程 步骤一&#xff1a;安…

Qt窗口与对话框

目录 Qt窗口 1.菜单栏 2.工具栏 3.状态栏 4.滑动窗口 QT对话框 1.基础对话框QDiaog 创建新的ui文件 模态对话框与非模态对话框 2.消息对话框 QMessageBox 3.QColorDialog 4.QFileDialog文件对话框 5.QFontDialog 6.QInputDialog Qt窗口 前言&#xff1a;之前以上…

自定义指令:Vue允许注册全局或组件级的自定义指令,以实现对常规DOM元素的复杂操作

简介 Vue自定义指令的概念 在Vue.js中,指令(Directives)是一些预定义的特殊属性,它们以v-为前缀,用于对DOM元素进行一些特殊的操作。而自定义指令则是用户自己定义的一种特殊功能,它可以像Vue内置的指令一样使用,以达到复用和模块化的目的。 自定义指令提供了一种机制,…

单双目视频转图片

视频转图片 视频转图片 输入文件夹路径&#xff0c;里面时mp4视频 输出的是每隔1秒提取到的视频帧 interval是每隔多少秒保存一张图片 import cv2 import osimg_count 1def save_frames(video_path, output_folder, interval):# 创建保存图片的文件夹if not os.path.exists(ou…

Linux驱动开发笔记(三)平台设备驱动

文章目录 前言一、Linux的设备模型1. 总线1.1 bus_type结构体1.2 注册/注销总线 2. 设备2.1 device结构体2.2 内核注册/注销设备 3. 驱动3.1 device_driver结构体3.2 注册/注销驱动 4. attribute属性文件4.1 attribute_group结构体4.2 设备属性文件4.3 驱动属性文件4.3. 总线属…

数组array 和 array的区别

问题 对于数组 array和&array有什么区别呢? 先说答案 array: 指向数组第一个数地址的指针 &array: 指向整个数组地址的指针 所以直接打印的话, 地址是一样的. 但是如果1的话, 那么array是增加sizeof(int)大小, &array是增加sizeof(int) * array.size() 测试 #i…

printf(“不喝酒就没得朋友可是只要偶一喝酒就喝倒一代朋友人生真的很矛盾“);

/*无线通讯语言模块测试PAST 2019 12 28 L298 CODE1871**/ #include <REG52.H> #include <intrins.H> #include "stdio.h" #define uint unsigned int #defi…

必应bing国内广告账户如何注册推广呢?

作为全球第二大搜索引擎&#xff0c;必应Bing以其庞大的用户基础和精准的定向能力&#xff0c;为企业提供了拓展市场的绝佳平台。对于许多企业来说&#xff0c;必应Bing广告账户的注册与推广流程可能显得复杂而繁琐。此时&#xff0c;您不妨考虑携手云衔科技&#xff0c;共同开…

一篇文章告诉你为什么要考TOGAF证书?

TOGAF&#xff08;The Open Group Architecture Framework&#xff09;是一种被广泛应用于企业架构领域的框架和方法论。TOGAF证书作为对TOGAF知识体系的认可架构师群体中受喜爱。本文将探讨为什么TOGAF证书如此受欢迎&#xff0c;并解释其在企业架构中的重要性。 TOGAF证书的…