html2canvas #x2B; jspdf实现页面导出成pdf

封装一个好用的页面导出 PDF 工具 Hook (html2canvas + jspdf)

在最近的一个项目中,遇到一个将页面内容(详情页)导出为 PDF的需求,但是好像目前没有直接把dom转成pdf这样一步到位的技术,所以自己封装了一个间接转换的方法,基于 Vue3 + TypeScript 的通用 Hook 封装,利用 html2canvas 和 jspdf 实现网页内容导出为 PDF,并解决了 滚动截断 、 清晰度不足 以及 自动分页 等常见问题。

一、 技术选型

  • html2canvas : 将 DOM 元素转换为 Canvas 图片。
  • jspdf : 将 Canvas 图片生成 PDF 文件。
  • 封装 : 使用 Hook 方式封装,方便复用。

二、 核心痛点与解决方案

在实现过程中,我们通常会遇到以下几个坑:

  1. 导出内容不全 :如果页面有滚动条,直接截图只能截取可视区域。
    • 解法 :在截图前将 DOM 高度设置为 auto ,并获取 scrollHeight 传递给 html2canvas 的 windowHeight 参数。
  2. 图片模糊 :默认截图出来的 PDF 很模糊。
    • 解法 :设置 scale: 2 ,提高 Canvas 的像素密度。
  3. PDF 分页问题 :长图直接放入 PDF 会被压缩变形。
    • 解法 :计算内容高度与 A4 纸高度的比例,通过循环 addPage() 实现自动分页切割。

三、 源码实现

新建文件 useExportPdf.ts,下载依赖 html2canvas 和 jspdf 然后引入:

/* by yours.tools - online tools website : yours.tools/zh/generatebtcwallets.html */ import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; /** * 导出页面为 PDF * @param dom 需要导出的 DOM 元素 * @param fileName 导出的文件名(不含后缀) */ export const useExportPDF = async (dom: HTMLElement, fileName: string) => { const element = dom; if (!element) { console.error('导出失败,未找到导出元素'); return; } // 1. 解决滚动截断问题:获取元素实际高度 const originalHeight = element.scrollHeight; // 临时设置高度为 auto,确保能截取到所有内容 const originalStyleHeight = element.style.height; element.style.height = 'auto'; try { // 2. 将 DOM 转换为 Canvas const canvas = await html2canvas(element, { useCORS: true, // 允许跨域图片 scale: 2, // 2倍缩放,解决模糊问题 scrollY: -window.scrollY, // 修正滚动条偏移 scrollX: 0, windowHeight: originalHeight, // 告诉 html2canvas 完整高度 }); // 3. 初始化 PDF 实例 // p: 纵向, mm: 单位毫米, a4: 纸张格式 const pdf = new jsPDF('p', 'mm', 'a4'); // A4 纸内容宽度(留边距) const imgWidth = 190; // 根据宽度计算等比例的高度 const imgHeight = (canvas.height * imgWidth) / canvas.width; // 获取 PDF 页面可用高度 const pdfPageHeight = pdf.internal.pageSize.getHeight(); // 4. 处理分页逻辑 let position = 0; // 第一页 pdf.addImage(canvas, 'PNG', 10, 10 - position, imgWidth, imgHeight); position += pdfPageHeight; // 这里简化处理,按页面高度分页 // 如果内容高度超过一页,循环添加新页 while (position < imgHeight) { pdf.addPage(); // 移动图片位置,实现视觉上的“接续” // 注意:这里简单的 position += pageHeight 可能需要根据实际情况调整, // 比如减去一些边距来防止文字被切断,Demo 中使用了简化的逻辑。 pdf.addImage(canvas, 'PNG', 10, 10 - position, imgWidth, imgHeight); position += pdfPageHeight; } // 5. 保存文件 pdf.save(`${fileName}.pdf`); } catch (error) { console.error('导出 PDF 异常:', error); } finally { // 6. 恢复原始样式 element.style.height = originalStyleHeight; } };

四、 如何在组件中使用

在 Vue 组件中,我们只需要获取到 DOM 引用,然后调用这个 Hook 即可。

/* by yours.tools - online tools website : yours.tools/zh/generatebtcwallets.html */ <a-button type="primary" @click="exportPDF" v-if="disabled"> 导出PDF </a-button>
import { useExportPDF } from '/@/hooks/exportpdf/useExportpdf'; // 导出的 DOM 元素 const pdfContainer = ref<HTMLDivElement>(null); // 导出 const exportPDF = async () => { loading.value = true; try { await useExportPDF(pdfContainer.value, 'xxxxpdf'); loading.value = false; } catch (e) { console.log(e); loading.value = false; } };

五、 值得注意的事项

  • html2canvas 将dom元素转成canvas图片的时候如果dom元素中有图片,需要解决跨域问题,这个一般来讲可以在服务端(图片源)设置 :
    图片的响应头(Response Header)必须包含 CORS 头,允许你的域名访问,或者Nginx配置下代理,或者前端解决的话就把图片转成Base64格式,但是如果图片比较多,就不建议前端解决了,第一个因为转图片格式图片一多就消耗更多时间,第二个是因为转成Base64格式的图片会增加文件大小。
  • 还有一个就是如果你想导致的内容之中,有些是不用导出,或者根据不同条件来区分是否导出可以使用 />。
  • 最终实现效果
    需要导出的页面

    导出的pdf

六、 总结

通过这个封装,我们实现了一个轻量级且功能完备的 PDF 导出工具。它不仅解决了最让人头疼的 长页面截断 问题,还通过 scale 参数保证了导出的清晰度。

七、 小思考

为啥img标签就能通过图片url加载图片,但是把图片转成Canvas就会出现跨域问题?
简单来说就是 标签只是“展示”数据,而 转成Canvas 需要“读取”数据 。浏览器的安全策略(同源策略)就是“看一眼”和“拿走数据”的区别
标签展示数据跟把图片转成转成Canvas浏览器都会请求图片,服务器返回图片数据。区别在于:
1. 标签加载

  • 请求头 :浏览器发起请求时, Origin 字段可能不被包含(或者是 null ),或者仅仅作为 Referer 发送。它通常被视为一个“简单请求”。

  • 响应头 :服务器返回图片数据。通常 不需要 包含 Access-Control-Allow-Origin 等 CORS 相关头信息。

  • 结果 :浏览器接收到数据,渲染引擎直接解码并在屏幕上绘制像素。JavaScript 无法接触到这些数据。
    2.开启 CORS 的情况( crossorigin="anonymous" 或 Canvas 请求)
    当你为了 Canvas 导出而给图片添加 crossorigin 属性,或者使用 JS fetch 请求图片时:

  • 请求头 :浏览器 强制添加 Origin: https://你的域名.com 字段,明确告诉服务器是谁在请求。

  • 响应头(关键差别) :

    • 如果服务器支持跨域 :必须返回 Access-Control-Allow-Origin: * 或 Access-Control-Allow-Origin: https://你的域名.com 。
    • 如果服务器不支持 :服务器可能正常返回了图片数据(状态码 200),但 缺少了 CORS 响应头 。
  • 结果 :

    • 如果 有 CORS 头:浏览器认为这份数据是“安全”的,允许 Canvas 读取和导出。
    • 如果 没有 CORS 头:虽然数据下载下来了,但浏览器(网络层或渲染层)会 拦截 这次加载,报错 CORS policy ,图片甚至可能直接裂开(加载失败),更别说画到 Canvas 上了。

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

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

相关文章

轻量级VLM也能SOTA?PaddleOCR-VL-WEB技术深度解析

轻量级VLM也能SOTA&#xff1f;PaddleOCR-VL-WEB技术深度解析 1. 引言&#xff1a;文档解析的效率与精度之争 在当前AI大模型快速发展的背景下&#xff0c;视觉-语言模型&#xff08;Vision-Language Model, VLM&#xff09;已成为复杂文档解析的核心技术。然而&#xff0c;大…

APISIX > AI 网关实现 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Qwen3-VL-2B行业应用:安防监控的异常行为检测

Qwen3-VL-2B行业应用&#xff1a;安防监控的异常行为检测 1. 引言&#xff1a;AI视觉理解在安防场景中的演进 随着城市化进程加快和公共安全需求提升&#xff0c;传统安防系统正从“被动录像”向“主动识别”转型。早期的视频监控依赖人工回看&#xff0c;效率低、响应慢&…

超实用技巧!快速掌握 Qwen2.5-7B 指令微调方法

超实用技巧&#xff01;快速掌握 Qwen2.5-7B 指令微调方法 1. 环境与资源概览 在进行大模型指令微调之前&#xff0c;确保具备合适的硬件和软件环境是成功的关键。本文基于预置镜像 单卡十分钟完成 Qwen2.5-7B 首次微调&#xff0c;提供一套高效、可复现的 LoRA 微调实践方案…

朔州市山阴应县右玉英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025

在全球化留学趋势持续升温的背景下,雅思考试已成为朔州市、山阴县、应县、右玉县学子通往海外名校的核心门槛。然而,当地雅思培训市场鱼龙混杂,考生普遍面临选课迷茫、优质资源匮乏、提分效率低下、个性化方案缺失等…

mysql 语句优化

# MySQL 语句优化方式详解 ## 📊 **一、SQL 编写优化** ### **1. 避免 SELECT ***```sql-- ❌ 不推荐SELECT * FROM users WHERE status = 1; -- ✅ 推荐:只取需要的列SELECT id, name, email FROM users WHERE sta…

Qwen2.5 API调用实战:Python集成与响应解析指南

Qwen2.5 API调用实战&#xff1a;Python集成与响应解析指南 1. 引言 1.1 业务场景描述 在当前大模型应用快速发展的背景下&#xff0c;如何高效地将大型语言模型&#xff08;LLM&#xff09;集成到实际产品中成为关键挑战。本文聚焦于 Qwen2.5-7B-Instruct 模型的本地部署与…

忻州市忻府原平定襄五台英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025

在雅思培训市场鱼龙混杂的当下,忻州市忻府、原平、定襄、五台等地的考生普遍面临选课迷茫、优质机构难甄别、提分技巧匮乏、个性化方案缺失等痛点。如何在众多教育机构中选出靠谱且性价比高的品牌,直接关系到考试成败…

实战案例解析CANFD如何突破CAN的速率瓶颈

实战解析&#xff1a;CAN FD如何破解传统CAN的带宽困局你有没有遇到过这样的场景&#xff1f;在调试一辆智能电动车的BMS系统时&#xff0c;发现电池数据上传延迟严重&#xff1b;或者在做ADAS融合感知时&#xff0c;摄像头目标框频繁丢帧——而排查下来&#xff0c;并非算法或…

Qwen3-4B模型安全:内容过滤与敏感词处理

Qwen3-4B模型安全&#xff1a;内容过滤与敏感词处理 1. 引言 1.1 AI 写作大师 - Qwen3-4B-Instruct 随着大语言模型在内容生成、代码编写和逻辑推理等领域的广泛应用&#xff0c;如何确保其输出的安全性成为工程落地中的关键挑战。基于阿里云最新发布的 Qwen/Qwen3-4B-Instr…

IsoAlgo管道轴测图引擎用户界面

为了方便用户使用IsoAlgo,提供一个简单的用户界面IsoAlgo简介 IsoAlgo是图核科技公司自主研发的管道轴测图引擎piping Isometric drawing generation Algorithms的简称,读作ISO阿狗或爱狗。IsoAlgo可以通过读取IDF/P…

通义千问2.5推理延迟高?GPU利用率提升实战指南

通义千问2.5推理延迟高&#xff1f;GPU利用率提升实战指南 在大模型应用日益普及的今天&#xff0c;Qwen2.5-7B-Instruct 凭借其强大的指令理解与生成能力&#xff0c;成为众多开发者构建智能对话系统的首选。然而&#xff0c;在实际部署过程中&#xff0c;不少用户反馈&#…

2026年丽江口碑好的污水处理咨询,污水处理施工,污水处理设计厂家品牌推荐清单 - 品牌鉴赏师

污水处理厂家推荐榜 推荐一:云南龙帜环境工程有限公司品牌介绍:云南龙帜环境工程有限公司是国家高新技术企业,同时担任云南省环保协会副会长单位等。它长期专注环保水处理,业务涵盖生活、工业等多种废水处理,以及…

如何一键将照片转卡通?DCT-Net人像卡通化模型全解析

如何一键将照片转卡通&#xff1f;DCT-Net人像卡通化模型全解析 1. 技术背景与核心价值 随着虚拟形象、社交娱乐和数字内容创作的兴起&#xff0c;人像卡通化技术逐渐成为AI图像生成领域的重要应用方向。用户希望通过简单操作&#xff0c;将真实人脸照片自动转换为风格统一、…

Qwen-Image-2512未来展望:语言驱动修图新时代

Qwen-Image-2512未来展望&#xff1a;语言驱动修图新时代 随着多模态大模型的持续演进&#xff0c;图像编辑正从“像素操作”迈向“语义操控”的全新时代。阿里通义千问团队推出的 Qwen-Image-2512 模型&#xff0c;作为 Qwen-VL 系列在视觉生成领域的最新迭代&#xff0c;不仅…

2026全铝定制厂家实力TOP10:铝合金衣柜选品攻略,这几家闭眼入不踩雷 - 深度智识库

在 2026 年的家居消费市场,健康环保与耐用实用成为消费者选购家具的核心诉求。铝合金衣柜、全铝衣柜、金属衣柜等全铝定制产品,凭借零甲醛释放、防水防潮、使用寿命长等突出优势,迅速占领家装市场的半壁江山。为了帮…

vivado2025新手避坑指南:环境搭建中的十大错误

Vivado 2025 新手避坑指南&#xff1a;从零搭建稳定开发环境的实战经验 你是不是也曾在安装 Vivado 的第一天就卡在启动界面&#xff1f; 是不是下载了几个小时的安装包&#xff0c;结果双击 xsetup.exe 却弹出一串看不懂的日志错误&#xff1f; 又或者好不容易装上了&…

如何用PyTorch-2.x-Universal-Dev-v1.0快速实现图像超分辨率任务?

如何用PyTorch-2.x-Universal-Dev-v1.0快速实现图像超分辨率任务&#xff1f; 1. 引言 1.1 业务场景与技术背景 在计算机视觉领域&#xff0c;图像超分辨率&#xff08;Super-Resolution, SR&#xff09;是一项关键任务&#xff0c;旨在从低分辨率图像中恢复出高分辨率、细节…

HY-MT1.5-1.8B部署实战:边缘计算场景应用

HY-MT1.5-1.8B部署实战&#xff1a;边缘计算场景应用 1. 引言 随着全球化进程的加速&#xff0c;跨语言沟通需求在企业服务、跨境电商、内容本地化等场景中日益增长。传统云端机器翻译方案虽然性能强大&#xff0c;但在延迟敏感型边缘计算场景中面临网络依赖高、响应慢、数据…

通义千问3-14B部署教程:Windows下Ollama配置避坑指南

通义千问3-14B部署教程&#xff1a;Windows下Ollama配置避坑指南 1. 引言 1.1 学习目标 本文旨在为开发者提供一份完整的 Qwen3-14B 模型在 Windows 系统下的本地部署指南&#xff0c;重点围绕 Ollama Ollama WebUI 的组合使用展开。通过本教程&#xff0c;你将掌握&#x…