好的,我给你整理一份 基于 JavaScript 的 HTML → PDF 转换完整指南,涵盖浏览器端、Node.js 环境以及常用库和技巧,便于快速实现网页或内容导出 PDF。
基于 JavaScript 的 HTML 到 PDF 转换指南
1️⃣ 常用场景
- 前端导出报表、发票、合同
- 服务端生成文档或账单
- 打印网页内容或生成静态备份
2️⃣ 实现方式概览
| 方法 | 适用环境 | 特点 | 常用库 |
|---|---|---|---|
| 浏览器端 JS | 浏览器 | 用户端直接生成 PDF,无需服务端 | jsPDF, html2canvas |
| Node.js | 服务端 | 生成 PDF 可自动化或批量处理 | puppeteer, playwright, pdfkit |
| API / 服务 | 任何环境 | 通过第三方 API 转换,快速简单 | pdfcrowd, html2pdf |
3️⃣ 浏览器端实现
3.1 使用 jsPDF + html2canvas
- 将 HTML 转为 Canvas,再导出 PDF
<div id="content">
<h1>标题</h1>
<p>这是导出 PDF 的内容</p>
</div>
<button id="download">下载 PDF</button>
<script src="https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
<script>
document.getElementById('download').onclick = async () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'pt', 'a4');
const content = document.getElementById('content');
const canvas = await html2canvas(content, { scale: 2 });
const imgData = canvas.toDataURL('image/png');
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
const imgProps = doc.getImageProperties(imgData);
const pdfHeight = (imgProps.height * pageWidth) / imgProps.width;
doc.addImage(imgData, 'PNG', 0, 0, pageWidth, pdfHeight);
doc.save('output.pdf');
};
</script>
优点:
- 简单,无需服务端
- 可导出任意 HTML 内容
缺点:
- 长页面分页处理复杂
- CSS 样式部分可能丢失
- 大页面生成 PDF 可能内存消耗高
3.2 使用 html2pdf.js(封装方案)
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<script>
document.getElementById('download').onclick = () => {
const element = document.getElementById('content');
html2pdf()
.set({ margin: 10, filename: 'output.pdf', html2canvas: { scale: 2 } })
.from(element)
.save();
};
</script>
html2pdf.js 底层仍使用 jsPDF + html2canvas,封装了分页、缩放和导出。
4️⃣ Node.js 服务端实现
4.1 使用 Puppeteer
- 基于 Chromium 的无头浏览器,可渲染完整 HTML 并生成 PDF
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
await page.pdf({
path: 'example.pdf',
format: 'A4',
printBackground: true
});
await browser.close();
})();
优点:
- 支持完整 CSS、JS 渲染
- 分页、页眉页脚、背景色可自定义
- 可处理长页面和动态内容
4.2 使用 Playwright
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.pdf({ path: 'example.pdf', format: 'A4' });
await browser.close();
})();
- Playwright 与 Puppeteer 类似,支持多浏览器
4.3 使用 PDFKit(纯 Node.js 绘制)
- 适合生成文本、图表等结构化 PDF,而不是 HTML 页面
const PDFDocument = require('pdfkit');
const fs = require('fs');
const doc = new PDFDocument();
doc.pipe(fs.createWriteStream('output.pdf'));
doc.fontSize(25).text('Hello PDFKit', 100, 100);
doc.end();
5️⃣ 导出技巧
- 处理长页面
- 浏览器端使用 html2canvas 分段截图
- Puppeteer/Playwright 可自动分页
page.pdf({ format: 'A4', printBackground: true })
- 保留 CSS
- 确保所有 CSS 已加载(字体、图片、背景色)
- Puppeteer 支持
printBackground: true
- 动态内容
- 等待 JS 渲染完成再导出:
await page.waitForSelector('#content'); - 自定义页眉/页脚
await page.pdf({ path: 'output.pdf', format: 'A4', displayHeaderFooter: true, headerTemplate: '<div style="font-size:12px">页眉</div>', footerTemplate: '<div style="font-size:12px">页脚</div>' });
6️⃣ 总结
| 场景 | 推荐方案 | 优缺点 |
|---|---|---|
| 前端单页内容导出 | jsPDF + html2canvas / html2pdf.js | 简单,但长页面分页复杂 |
| 服务端生成 PDF | Puppeteer / Playwright | 高保真渲染,支持长页面、动态 JS |
| 文本/图表生成 | PDFKit | 可绘制 PDF 元素,HTML 转换不便 |
总结:
- 前端导出适合用户即时下载报表
- 服务端生成适合批量、自动化或高保真 PDF