vue中使用html2canvas配合jspdf导出pdf(以及在导出时遇到的导出样式问题)

指定页面中导出为pdf格式并打包,使用html2canvas先转为图片格式,在利用jspdf转为pdf,最后下载打包为本地压缩包

yarn add html2canvas
yarn add jspdf
1. 注册一个插件并挂载
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {install(Vue, options) {Vue.prototype.getPdf = function (dom) {return new Promise((resolve, reject) => {html2Canvas(dom.$el, {allowTaint: true,scale: 2,dpi: 300,}).then(function (canvas) {let contentWidth = canvas.width;let contentHeight = canvas.height;let pdfWidth = 595.28; // A4 width in pixelslet pdfHeight = (pdfWidth / contentWidth) * contentHeight;let pageData = canvas.toDataURL('image/jpeg', 1.0);let PDF = new JsPDF('p', 'pt', 'a4');let scale = pdfWidth / contentWidth;PDF.addImage(pageData, 'JPEG', 0, 0, pdfWidth, pdfHeight);let remainingHeight = pdfHeight;while (remainingHeight < contentHeight) {PDF.addPage();let offsetY = -remainingHeight * scale;PDF.addImage(pageData, 'JPEG', 0, offsetY, pdfWidth, pdfHeight);remainingHeight += pdfHeight;}PDF.save('export.pdf'); //直接下载// resolve(PDF.output('blob')); //转为blob格式 返回合并下载}).catch(reject);});};}
}
2. 页面使用
DownPDFAndFile(){this.getPdf('传入ref或者是id')
}

以上正常导出步骤 封装方法 使用 但是如果你的项目中用的是rem布局或者是适配方法,样式或者字体没有显示出来被盖掉请往下看

3.由于在项目中用rem做了适配导致样式变形

在这里插入图片描述

4. 我们可以在html2canvas生成图片时把对应的样式或者添加类名,在生成图片前修改样式,转换为pdf后恢复初始样式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
/*** @param {*} 添加样式类名*/
function removeChildrenWithClass(parent, className) {var children = parent.childNodes;if (parent.classList && parent.classList.contains('form_view_item')) {parent.childNodes.forEach((item) => {item.className += ' is_to_print'})}for (var i = 0; i < children.length; i++) {if (children[i].classList && children[i].classList.contains('isprint')) {children[i].style.display = 'block'if (children[i].classList.contains('is_toprint')) children[i].style.display = 'block'}if (children[i].classList && children[i].classList.contains('form_view_title')) {children[i].style.marginTop = '25px'}if (children[i].classList && children[i].classList.contains(className)) {children[i].style.display = 'none'} else if (children[i].childNodes) {removeChildrenWithClass(children[i], className);}}
}
/*** @param {*} 恢复初始样式*/
function restoreOriginalState(parent, className) {var children = parent.childNodes;if (parent.classList && parent.classList.contains('form_view_item')) {parent.childNodes.forEach((item) => {item.classList.remove('is_to_print');});}for (var i = 0; i < children.length; i++) {if (children[i].classList && children[i].classList.contains(className)) {children[i].style.display = '';}if (children[i].classList && children[i].classList.contains('form_view_title')) {children[i].style.marginTop = '';}if (children[i].classList && children[i].classList.contains('isprint')) {children[i].style.display = 'none';}if (children[i].childNodes) {restoreOriginalState(children[i], className);}}
}
export default {install(Vue, options) {Vue.prototype.getPdf = function (dom) {return new Promise((resolve, reject) => {removeChildrenWithClass(dom.$el, 'noprint');html2Canvas(dom.$el, {allowTaint: true,//如果不要求清晰度可以去掉scale: 2,  //按比例增加分辨率 dpi: 300, //将分辨率提高到特定的 DPI}).then(function (canvas) {restoreOriginalState(dom.$el, 'noprint')let contentWidth = canvas.width;let contentHeight = canvas.height;let pdfWidth = 595.28; // A4 width in pixelslet pdfHeight = (pdfWidth / contentWidth) * contentHeight;let pageData = canvas.toDataURL('image/jpeg', 1.0);let PDF = new JsPDF('p', 'pt', 'a4');let scale = pdfWidth / contentWidth;PDF.addImage(pageData, 'JPEG', 0, 0, pdfWidth, pdfHeight);let remainingHeight = pdfHeight;while (remainingHeight < contentHeight) {PDF.addPage();let offsetY = -remainingHeight * scale;PDF.addImage(pageData, 'JPEG', 0, offsetY, pdfWidth, pdfHeight);remainingHeight += pdfHeight;}PDF.save('export.pdf'); //直接下载// resolve(PDF.output('blob')); //转为blob格式 返回合并下载}).catch(reject);});};}
}
5. 修改完后导出正常

在这里插入图片描述

6. 如果需求是直接下载以下就忽略,如果需求是打包为本地压缩包请继续
// 引入使用attachDownload方法
// 下载事件
async DownPDFAndFile() {const pdfinfo = await this.getPdf('传入ref或者是id')const pdfList = [//参数字段自行修改 为attachDownload 中的字段对应{id: "...",data: pdfinfo,},];const ImageList = []const VideoList = []const ImageAndVideoAndPdfList = [...pdfList,...ImageList,...VideoList]const { downloadStatus } = await this.is_downFile(ImageAndVideoAndPdfList);// downloadStatus 这个状态为下载状态 true为完成 可以自行添加业务},
// 下载方法
async is_downFile(list) {if (list.length > 0) {const config = {downloadList: list,suffix: "病历编辑.zip",};const { downloadStatus } = await attachDownload(config);return { downloadStatus };}},
7. 打包下载使用的是JSZip 和 FileSaver
yarn add jszip
yarn add file-saver
// attachDownload.js
import JSZip from "jszip";
import FileSaver from "file-saver";
export async function attachDownload(config) {const { downloadList, suffix } = configconst zip = new JSZip();const cache = {};let downloadStatus = falseconst downloadPromises = downloadList.map(async (item) => {try {if (item.url) {let data;if(item.type=='.pdf'){data = item.data;}else{data = await getImgArrayBuffer(item.url);}zip.folder(suffix).file(`${item.Title}_${item.FileID}` + item.type, data, { binary: true });cache[item.id] = data;} else {throw new Error(`文件${item.fileName}地址错误,下载失败`);}} catch (error) {console.error("文件获取失败", error);}});try {await Promise.all(downloadPromises);const content = await zip.generateAsync({ type: "blob" });FileSaver.saveAs(content, suffix);downloadStatus = truereturn {downloadStatus}} catch (error) {console.error("文件压缩失败", error);}
}
async function getImgArrayBuffer(url) {const response = await fetch(url);if (!response.ok) {throw new Error(`请求失败: ${response.status}`);}return await response.blob();
}

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

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

相关文章

记一次生产系统每隔10小时(36000000毫秒)固定进行一次Full GC排查思路

一、 背景描述 某个应用在生产环境通过系统监控发现&#xff0c;应用每隔10小时就会触发一次Full GC&#xff0c;该系统当时承接的业务量并不大&#xff0c;而且固定10小时就会进行Full GC&#xff0c;通过监控时间轴发现Full GC频率很规律&#xff0c;直觉告诉我这不是JVM自身…

js实现根据字符串生成颜色

在JavaScript中&#xff0c;你可以根据给定的字符串生成一种颜色。这种操作通常需要将字符串转换为颜色代码&#xff0c;如十六进制颜色代码。下面是一个简单的示例&#xff0c;我们使用字符串的字符码来生成颜色&#xff1a; function stringToColor(str) {let hash 0;for (…

寒假 day1

1、请简述栈区和堆区的区别? 2、有一个整形数组:int arr[](数组的值由外部输入决定)&#xff0c;一个整型变量: x(也 由外部输入决定)。要求: 1)删除数组中与x的值相等的元素 2)不得创建新的数组 3)最多只允许使用单层循环 4)无需考虑超出新数组长度后面的元素&#xff0c;所以…

nginx请求头处理

不啰嗦,直接上代码 删除Content-Type #清理Content-Type types {}设置默认的content-type default_type application/wasm; 添加请求头 add_header header_name header_value; 隐藏请求头 proxy_hide_header heade_name;

使用PyMysql模块连接mysql

PyMysql模块的安装 在命令行窗口下执行下行命令即可 linux:sudo pip3 install PyMySQL windows: pip3 install PyMysql 连接数据库并查询数据 # 导入模块 import pymysql# 与数据库建立连接 my_db pymysql.connect(host"127.0.0.1", user"root", pas…

Authentication Persistence and Session Management

翻译版本 【spring-security 6.2.1 】session-managemen Authentication Persistence and Session Management 一旦您获得了一个正在对请求进行身份验证的应用程序&#xff0c;就必须考虑如何在未来的请求中持久化和恢复所产生的身份验证。 默认情况下&#xff0c;这是自动完…

网络原理TCP/IP(4)

文章目录 面向字节流粘包问题异常情况TCP小结 面向字节流 创建⼀个TCP的socket,同时在内核中创建⼀个发送缓冲区和⼀个接收缓冲区; • 调⽤write时,数据会先写⼊发送缓冲区中; • 如果发送的字节数太⻓,会被拆分成多个TCP的数据包发出; • 如果发送的字节数太短,就会先在缓…

【lesson40】理解文件系统

文章目录 问题磁盘结构&#xff08;物理&#xff09;磁盘的存储结构磁盘的抽象结构 问题 1.有没有没有被打开的文件&#xff1f;当然有 在哪里呢&#xff1f;磁盘中也叫磁盘级文件 2.学习磁盘级别文件的侧重点在哪&#xff1f; 站在单个文件角度: 这个文件在哪里&#xff1f…

【Linux】权限管理

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一 、Linux中的用户1.1 Linux用户分类1.2 用户转换1.3 指令提权 二、Linux权限管…

LeetCode:88. 合并两个有序数组(双指针 Java)

目录 88. 合并两个有序数组 题目描述&#xff1a; 实现代码与解析&#xff1a; 双指针 原理思路&#xff1a; 88. 合并两个有序数组 题目描述&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 num…

vscode git stash apply stash@{1}不生效

解决办法 在stash{1}前后加上引号 git stash apply “stash{1}“即可成功恢复指定的stash

企业网络采用SD-WAN的优势

近年来&#xff0c;SD-WAN成为企业网络领域的一项热门技术&#xff0c;为传统网络带来了新的变革。SD-WAN&#xff08;Software Defined Wide Area Network&#xff0c;软件定义广域网&#xff09;以其灵活性、可管理性和低成本而备受青睐。它不仅能够创建成熟的专用网络&#…

MySQL 教程 2.3

MySQL DELETE 语句 你可以使用 DELETE FROM 命令来删除 MySQL 数据表中的记录。 你可以在 mysql> 命令提示符或 PHP 脚本中执行该命令。 语法 以下是 DELETE 语句从 MySQL 数据表中删除数据的通用语法&#xff1a; DELETE FROM table_name WHERE condition; 参数说明&…

IP风险画像在企业网络安全中应用

随着企业数字化的不断深入&#xff0c;网络安全问题日益突显。IP风险画像作为一种综合性的网络安全工具&#xff0c;为企业提供了更全面的风险评估和防范手段。本文将结合一个实际案例&#xff0c;深入探讨IP风险画像在企业网络安全中的成功应用。 案例背景 一家大型金融机构…

Like his father, he was driving a car called Bluebird. chatGPT学英语

chatGPT学英语 1、翻译为中文&#xff1a;像他父亲一样&#xff0c;他也在开一辆叫做“蓝鸟”的车。 2、时态分析&#xff1a;这是一个过去进行时的句子&#xff0c;句子语法是正确的。 3、句子结构分析&#xff1a; 主句&#xff1a;he was driving a car called Bluebird.…

IP数据云识别真实IP与虚假流量案例

随着互联网的普及&#xff0c;企业在数字领域面临着越来越复杂的网络威胁。为了保护网站免受虚假流量和恶意攻击的影响&#xff0c;许多企业正在采用IP数据云。本文将结合一个真实案例&#xff0c;深入探讨IP数据云如何成功准确地识别真实用户IP和虚假流量IP&#xff0c;提高网…

Oracle 面试题 | 09.精选Oracle高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

vue3 之 组合式API—reactive和ref函数

ref&#xff08;&#xff09; 作用&#xff1a;接收简单类型或者对象类型的数据传入并返回一个响应式的对象 核心步骤&#xff1a; 1️⃣ 从 vue 包中导入 ref 函数 2️⃣在 <script setup>// 导入import { ref } from vue// 执行函数 传入参数 变量接收const count …

【Python】【完整代码】解析Excel 文件中的内容并检查是否包含某字符串,并返回判断结果

示例&#xff1a; 开发需求&#xff1a;解析Excel 文件中的内容并检查是否包含 "Fail" 字符&#xff0c;若没有则返回True&#xff0c;若有则返回False 实现代码&#xff1a; #!/usr/bin/env python3 # -*- encoding: utf-8 -*-File : check_excel_for_fail.py Ti…

记录首次使用yolov8-obb

1.数据格式 之前使用的数据格式是yolov5_obb的数据格式&#xff0c;然后需要转数据格式&#xff1a; 目前的数据只支持四个坐标点标注的数据&#xff0c;参考&#xff1a;If a corner of the rotate rectangle is out of the image range, How to annotate the image? Issu…