聊到 Vue 项目里“导出 PDF”这个需求,我第一反应就是 jsPDF。这几乎是前端绕不开的一个库,配合 html2canvas 能把任意网页区域截成图片再生成 PDF。很多朋友一开始都会去试: window.print() 调浏览器打印、或者是用各种现成的 PDF 库,但真正落地时才发现坑一个接一个。这篇我打算把 Vue 里用 jsPDF 把网页转成 PDF 的完整思路、代码实现、分页算法和踩坑记录一次性讲透,从单页截图到多页报表,从模糊问题到元素被截断,尽量让每个看的人都能直接照着改出能用的版本。
适合谁来参考呢?一类是刚接手后台管理系统、正在做报表导出功能的同学;一类是已经在用 jsPDF 但是遇到多页内容、跨域图片、清晰度这类问题卡住的人。我会把方案选型的逻辑先讲清楚,再给完整可运行的代码,然后针对高频问题逐条排查。
1. 方案选型:为什么我最终选了 jsPDF + html2canvas
1.1 先搞清楚需求到底要解决什么
网页转 PDF 这个需求,表面上是“把页面变文件”,实际上背后有几种完全不同的场景。如果是商品详情页、长图文海报,你要的是“所见即所得”,页面长什么样导出后就什么样;如果是数据报表、结算单、成绩单,你要的是“按固定的纸张尺寸分页”,内容跨页时还要考虑标题行重复、表格线是否断裂;如果是电子合同、发票单据,那可能还要精确控制边距、留白、签章位置。
我遇到的典型场景是某后台管理系统里的“导出订单汇总报表”功能。页面里有一张宽表格、一堆统计卡片、还有图表,产品的要求是点击按钮后生成一份排版整齐的 PDF,不能出现内容压边、文字模糊、表格行被拦腰截断。这类需求用浏览器打印其实也能凑合,但打印时用户需要手动选纸张、调边距,体验不可控,而且不同浏览器打印出来的效果差异巨大。jsPDF 则是完全在代码里控制输出,稳定性好,适合嵌入业务系统。
1.2 市面主流方案的优劣对比
我试过四种常见路线:原生打印、jsPDF + html2canvas、pdfmake、html2pdf.js。它们的适用场景差别挺大。
| 方案 | 原理 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|---|
| window.print() / CSS print | 调用浏览器打印引擎 | 零依赖,文字是矢量,排版清晰 | 依赖用户操作,分页控制弱,浏览器兼容差异大 | 单页文档、需要用户自己保存的场景 |
| jsPDF + html2canvas | DOM 转 canvas 截图为图片,再写入 PDF | 所见即所得,支持任意复杂样式,可控性强 | 体积较大,长页面内存占用高,生成的是图片型 PDF | 页面截图型导出、复杂样式报表 |
| pdfmake | 用 JSON 描述文档结构,直接生成 PDF | 文档型 PDF,文字可选中,体积小 | 不能直接截网页,样式需要重新用 API 描述 | 结构化的表格、文档、简历 |
| html2pdf.js | 封装了 jsPDF 和 html2canvas | 上手快,API 简单 | 多页分页处理比较粗糙,复杂布局容易错位 | 快速原型、简单页面导出 |
我最后选 jsPDF + html2canvas,核心原因就一个:我们项目里的页面是动态渲染的,有很多卡片、图表、业务组件,如果改用 pdfmake 重新描述文档结构,等于页面写两遍,维护成本直接翻倍。截图的思路虽然生成的是图片型 PDF,但胜在效果和页面完全一致,改动成本极低。只要在细节上把分页和清晰度处理好,完全能满足业务需求。
不过也要提醒一句,如果你的需求是“生成一份文字可复制、可搜藏的正式文档”,那还是尽早用 pdfmake 这类文档型方案更合适,图片型 PDF 在这方面是天生短板。
2. jsPDF 核心概念与基础准备
2.1 jsPDF 到底是怎么工作的
jsPDF 本身做的事情其实很简单:创建一个 PDF 文档对象,然后往里面添加文字、图片、线条等元素,最后保存成文件。它支持多种坐标系单位,最常用的是 pt (磅)和 mm (毫米)。在浏览器端,它会利用浏览器的 Blob 和 URL 能力生成下载链接。
这里要理解一个关键点:jsPDF 不能直接“吃掉”网页 DOM。它不认识 Vue 组件、不认识 CSS,甚至不认识 HTML 标签。它只接受图片或者文本。所以要让网页变成 PDF,我们得先借助 html2canvas 把 DOM 渲染成 canvas 画布,再转成图片数据,最后交给 jsPDF 排版。
用一个生活化的类比来说,html2canvas 相当于一台照相机,把当前网页这一整块场景拍成照片;jsPDF 相当于打印机和相册排版工具,负责把照片按照 A4 纸的大小排放好。所以你最终拿到的 PDF,本质上是一本相册册子,而不是可编辑的 Word 文档。想通这一点后,后续所有的分页、尺寸、清晰度问题就都好解释了。
2.2 安装与最小示例
新版本 jsPDF 官方文档推荐直接走 npm 安装,Vue 项目里就两条命令:
npm install jspdf
npm install html2canvas
这里提醒一下:html2canvas 的版本更新节奏和 jsPDF 不完全同步,我曾经用过 html2canvas 的某个较新版本,发现某些 CSS 属性渲染异常,后来固定到 1.4.1 版本反而稳定。如果你跟着官方文档跑最小示例发现样式对不上,可以先试试锁版本。
先看一个最简的使用流程:
import { jsPDF } from 'jspdf'
import html2canvas from 'html2canvas'
const exportPdf = async () => {
const dom = document.getElementById('pdf-content')
// 把 DOM 画成 canvas
const canvas = await html2canvas(dom, {
scale: 2,
useCORS: true,
backgroundColor: '#ffffff'
})
// 生成图片数据
const imgData = canvas.toDataURL('image/jpeg', 1.0)
// 创
1320




被折叠的 条评论
为什么被折叠?



