前端实现 HTML 网页转 PDF 并导出

news/2025/1/13 8:57:37/文章来源:https://www.cnblogs.com/burc/p/18568288

有个新需求,当点击【下载】按钮时,直接将当前 html页面下载为 PDF。通过 html2canvas + jsPDF 可实现PDF单页下载,甚至是多页下载,记录分享一下~ 最后有源码,可自取🫡

html2canvas

html2canvas官网在这:html2canvas - Screenshots with JavaScript

html2canvas 是一个 HTML 渲染器。该脚本允许你直接在用户浏览器截取页面或部分网页的“屏幕截屏”,通过读取 DOM 以及应用于元素的不同样式,将当前页面呈现为 canvas 图像

安装 html2canvas

npm install --save html2canvas

截取页面生成canvas,并将其插入页面中

html2canvas(document.body}).then(function(canvas) {document.body.appendChild(canvas);
});

注意:受限于浏览器的实现,HTML 的 canvas 元素也有高度限制⚠ 可参考 canvas 最大画布尺寸 - MDN

  • Chrome 和 Firefox 等现代浏览器,canvas 的最大尺寸通常限制在 32767 像素,这也是 WebGL 和 2D canvas 的共同限制。超过这个值会导致 canvas 生成失败,抛出错误,或者显示空白内容。
  • 老版本的 IE 对 canvas 尺寸限制较为严格,一般在 8192 像素上下。现代版本的 Edge 则与 Chrome 的限制类似

jsPDF

jsPDF文档可以看这:GitHub - parallax/jsPDF: Client-side JavaScript PDF generation for everyone.

安装 jspdf

npm install jspdf --save

API也很简单,下面是个生成文本和图片的PDF样例

// jsPDF 下载文本图片PDF
const downLoadPdf = () => {// 三个参数,第一个方向,第二个单位,第三个尺寸 'a4' = [595.28,841.89]const doc = new jsPDF('', 'pt', [500, 1000])// 字体大小doc.setFontSize(50)// 文本,左边距,上边距doc.text('Hello world!', 10, 50)// base64,图片类型,左边距,上边距,宽度,高度doc.addImage(base64, 'PNG', 10, 60, 400, 200)doc.save('a4.pdf')
}

注意: jsPDF 生成的 PDF 默认以 pt (point) 为单位,单页的最大高度通常限制在 14400 pt。超过这个高度可能导致生成的 PDF 无法正确渲染或浏览器崩溃⚠

html2canvas + jsPDF 实现页面下载

单页下载(自适应纸)

PDF页面的宽高 采用 canvas的宽高

  • canvas.height >= canvas.width,采用 portrait 纵向页面
  • canvas.width > canvas.height,采用 landscape 横向页面

如果页面很长的话,单页下载就会生成一张长长的PDF。注意!超过限制就会显示空白页面, jsPDF 生成的 PDF单页最大高度为 14400pt⚠

canvas也有最大高度限制 32767像素,如果页面过长的话,通过 html2canvas 生成 canvas会失败

const downLoadPdfAutoSingle = () => {html2canvas(document.body, {scale: window.devicePixelRatio * 2, // 使用设备的像素比 * 2}).then(canvas => {// 返回图片dataURL,参数:图片格式和清晰度(0-1)const pageData = canvas.toDataURL('image/jpeg', 1.0)const pageWidth = canvas.widthconst pageHeight =  canvas.heightconst orientation = canvas.height >= canvas.width ? 'portrait' : 'landscape'  // portrait 表示纵向,landscape表示横向const pdf = new jsPDF(orientation, 'pt', [pageWidth, pageHeight])// addImage后两个参数控制添加图片的尺寸,此处将页面高度按照a4纸宽高比列进行压缩pdf.addImage(pageData,'JPEG',0,0,pageWidth,pageHeight)pdf.save('下载一页PDF(自适应纸).pdf')})
}

单页下载(A4纸)

已知:A4纸的宽度 和 canvas的宽度高度。可得 canvas在A4纸上占用的总高度(A4纸尺寸为宽 595.28pt,高 841.89pt)

如果页面很长的话,单页下载就会生成一张长长的PDF。注意!超过限制就会显示空白页面, jsPDF 生成的 PDF单页最大高度为 14400pt⚠

canvas也有最大高度限制 32767像素,如果页面过长的话,通过 html2canvas 生成 canvas会失败

const downLoadPdfA4Single = () => {html2canvas(document.body).then(canvas => {// 返回图片dataURL,参数:图片格式和清晰度(0-1)const pageData = canvas.toDataURL('image/jpeg', 1.0)// 方向纵向,尺寸ponits,纸张格式 a4 即 [595.28, 841.89]const A4Width = 595.28const A4Height = 841.89 // A4纸宽const pageHeight = A4Height >= A4Width * canvas.height / canvas.width ? A4Height :  A4Width * canvas.height / canvas.widthconst pdf = new jsPDF('portrait', 'pt', [A4Width, pageHeight])// addImage后两个参数控制添加图片的尺寸,此处将页面高度按照a4纸宽高比列进行压缩pdf.addImage(pageData,'JPEG',0,0,A4Width,A4Width * canvas.height / canvas.width,)pdf.save('下载一页PDF(A4纸).pdf')})
}

多页下载(自适应纸)

由于 jsPDF 单页最大高度的限制 又或是 需求层面,我们需要实现自动分页下载

我们设置一页PDF页面宽度为canvas.width,高度为canvas.width * 1.3

分页思路:每个PDF页面都显示一张 canvas 图,只不过是计算偏移量,每个PDF页面显示的是 canvas 的不同位置

问题来了,如何创建一个新的PDF页面呢?可以使用 jsPDF 的pdf.addPage()

const downLoadPdfAutoMultiple = () => {const ele = document.bodyhtml2canvas(ele, {scale: window.devicePixelRatio * 2, // 使用设备的像素比 * 2}).then(canvas => {let position = 0 //页面偏移const autoWidth = canvas.width // 一页纸宽度const autoHeight = canvas.width * 1.3 // 一页纸高度// 一页PDF可显示的canvas高度const pageHeight = (canvas.width * autoHeight) / autoWidth// 未分配到PDF的canvas高度let unallottedHeight = canvas.height// canvas对应的PDF宽高const imgWidth = canvas.widthconst imgHeight = canvas.heightconst pageData = canvas.toDataURL('image/jpeg', 1.0)const pdf = new jsPDF('', 'pt', [autoWidth, autoHeight])// 当canvas高度 未超过 一页PDF可显示的canvas高度,无需分页if (unallottedHeight <= pageHeight) {pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)pdf.save('下载多页PDF(自适应纸).pdf')return}while (unallottedHeight > 0) {pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)unallottedHeight -= pageHeightposition -= autoHeightif (unallottedHeight > 0) {pdf.addPage()}}pdf.save('html2canvas+jsPDF下载PDF.pdf')})
}

多页下载(A4纸)

由于 jsPDF 单页最大高度的限制 又或是 需求层面,我们需要实现自动分页下载

我们设置一页PDF页面的宽高为A4纸尺寸,即宽 595.28pt,高 841.89pt

分页思路:每个PDF页面都显示一张 canvas 图,只不过是计算偏移量,每个PDF页面显示的是 canvas 的不同位置

问题来了,如何创建一个新的PDF页面呢?可以使用 jsPDF 的pdf.addPage()

const downLoadPdfA4Multiple = () => {const ele = document.bodyhtml2canvas(ele, {scale: 2, // 使用设备的像素比}).then(canvas => {let position = 0 //页面偏移const A4Width = 595.28 // A4纸宽度const A4Height = 841.89 // A4纸宽// 一页PDF可显示的canvas高度const pageHeight = (canvas.width * A4Height) / A4Width// 未分配到PDF的canvas高度let unallottedHeight = canvas.height// canvas对应的PDF宽高const imgWidth = A4Widthconst imgHeight = (A4Width * canvas.height) / canvas.widthconst pageData = canvas.toDataURL('image/jpeg', 1.0)const pdf = new jsPDF('', 'pt', [A4Width, A4Height])// 当canvas高度 未超过 一页PDF可显示的canvas高度,无需分页if (unallottedHeight <= pageHeight) {pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)pdf.save('下载多页PDF(A4纸).pdf')return}while (unallottedHeight > 0) {pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)unallottedHeight -= pageHeightposition -= A4Heightif (unallottedHeight > 0) {pdf.addPage()}}pdf.save('下载多页PDF(A4纸).pdf')})
}

源码

GitHub - burc-li/vue-pdf: HTML 转 PDF下载(html2canvas 和 jsPDF实现)

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

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

相关文章

AI应用实战课学习总结(5)回归分析预测实战

本文介绍了机器学习中的起点:回归分析,并进行了一个电商用户生命周期价值(LTV)的分析预测实战,最后还进行了多种回归模型的拟合效果对比,相信你会有一个直观的印象。大家好,我是Edison。 最近入坑黄佳老师的《AI应用实战课》,记录下我的学习之旅,也算是总结回顾。 今天…

Gitlab Runner安装与配置

由于格式和图片解析问题,为了更好阅读体验可前往 阅读原文本篇使用Docker安装Gitlab runner进行runner的安装和注册,其他方式请参考官方文档非Docker安装Gitlab runner请确保runner版本和gitlab版本兼容以及docker相关版本兼容问题下载镜像 docker pull gitlab/gitlab-runner…

笔记本电脑清灰以及升级硬盘与内存

1、工具准备(1)螺丝刀:最好使用手柄较粗(容易发力)、有磁吸(螺丝不易掉)、以及批头可以替换的螺丝刀。(2)撬片:拆机常用的是三角撬片,越薄越好;没有的话也可以用废弃的银行卡替代。(3)磁吸定位板:用于存放螺丝,没有的话也可以用瓶盖替代。(4)气吹与毛刷:用于…

读量子霸权02数字时代的终结

2000年前希腊人创造的安提基西拉仪器是计算机雏形,可计算月球运转。安提基西拉代表古代模拟宇宙巅峰。巴比奇未实现最先进机械计算机梦想。图灵被誉为“计算机科学之父”,提出图灵机概念。数字计算机比模拟计算机准确。图灵测试提出机器能否像人思考。1. 爱琴海的海底 1.1. 2…

行为树(BehaviorTree )的实现与应用

前言 我最近学习使用C#脚本实现Unity行为树,并使用行为树实现了对“空洞骑士”中,“假骑士”的AI行为逻辑的简单实现。本文主要记录了在这个过程中的一些要点。 行为树的原理及实现教程来自这位大佬的博客:游戏AI行为决策——Behavior Tree(行为树) 一、运作逻辑 行为树的…

48. django下载与基本使用

1.版本 django1.x:默认不支持异步 django2.x:默认不支持异步 django3.x:自带异步功能 2. 下载 2.1 pip安装pip install django==3.2.122.2 安装注意事项 计算机名称不能出现中文 注意python解释器版本与django版本的兼容性 项目中的文件名称不能出现中文 多个项目文件尽量不…

互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(一):从.NET IoT入门开始

前言 为什么我会想着制作一个智能桌面机器人呢?自问自答一下,看过我之前文章的小伙伴应该都知道我之前有为稚晖君开源的ElectronBot桌面机器人开发过一个桌面上位机软件叫电子脑壳,由于ElectronBot桌面机器人必须连接电脑才能使用,所以限制比较多,网友又对独立版本的桌面机…

C#进阶-在Ubuntu上部署ASP.NET Core Web API应用

随着云计算和容器化技术的普及,Linux 服务器已成为部署 Web 应用程序的主流平台之一。ASP.NET Core 作为一个跨平台、高性能的框架,非常适合在 Linux 环境中运行。本篇博客将详细介绍如何在 Linux 服务器上部署 ASP.NET Core Web API 应用,包括部署准备、应用发布、配置反向…

【CodeForces训练记录】Codeforces Round 996 (Div. 2)

训练情况赛后反思 开局连WA就知道这把完蛋了,应该要掉大分了,A题没考虑清楚,B题犯傻了一时间没看出来结论 A题 当且仅当两个人贴贴的时候,轮到谁走谁就输,后手可以把先手逼到两边,如果两人之间有一段距离,两人都必须往中间靠,如果两个人都往同一边走距离不变为无效操作…

2025 特斯拉 焕新 Model Y 增减配置详细参数对比分析图解 All In One

2025 特斯拉 焕新 Model Y 增减配置详细参数对比分析图解 All In One2025 特斯拉 焕新 Model Y 增减配置详细参数对比分析图解 All In One 焕新 Model Y 增配风阻降低到 0.22 Cd ✅ 车身变长到 4797 mm ✅ 车头保险杠新增一颗摄像头 ✅ 新增前排座椅通风 ✅ 新增后排座椅电动折…

Kernel Memory 让 SK 记住更多内容

Kernel Memory (KM) 是一种多模态 AI 服务,专注于通过自定义的连续数据混合管道高效索引数据集。它支持检索增强生成(RAG)、合成记忆、提示工程以及自定义语义记忆处理。KM 支持自然语言查询,从已索引的数据中获取答案,并提供完整的引用和原始来源链接。 通过 KM 我们可以…

大普时钟模块(Clock Module)

时钟模块(Clock Module) 同步精度高、保持能力强、温度稳定度高、频率准确度高、短稳性能强。 CM11T系列时钟模块,内置TCXO、超宽温,同步精度50ns CM55、CM22系列时钟模块,内置OCXO、超高精度 CM30系列时钟模块,内置OCXO、高频低噪 CM66系列时钟模块,内置OCXO+GNSS接收机 …