一、推荐方案:html2canvas + jsPDF(图片式PDF)
javascript
javascript
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
const exportPDF = async (elementId, fileName) => {
const element = document.getElementById(elementId);
// 1. 将DOM转为Canvas
const canvas = await html2canvas(element, {
scale: 2, // 提升清晰度
useCORS: true, // 允许跨域图片
logging: true, // 调试时开启
});
// 2. Canvas转图片数据
const imgData = canvas.toDataURL('image/png', 1.0);
// 3. 计算PDF尺寸
const pdf = new jsPDF('p', 'mm', 'a4');
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const imgRatio = canvas.width / canvas.height;
// 4. 自动适应页面大小
let imgHeight = pageHeight;
let imgWidth = pageWidth;
if (pageWidth / imgRatio < pageHeight) {
imgWidth = pageWidth;
imgHeight = imgWidth / imgRatio;
} else {
imgHeight = pageHeight;
imgWidth = imgHeight * imgRatio;
}
// 5. 添加图片到PDF
pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight);
// 6. 保存文件
pdf.save(`${fileName}.pdf`);
};
// 使用示例
exportPDF('export-container', 'report');
二、进阶方案:jsPDF内置HTML渲染(矢量文本)
javascript
javascript
import { jsPDF } from "jspdf";
const exportPDF = async () => {
const doc = new jsPDF('p', 'pt', 'a4');
// 1. 获取需要导出的HTML元素
const element = document.getElementById('content');
// 2. 直接渲染HTML到PDF(需要配合html2canvas)
await doc.html(element, {
callback: (doc) => doc.save('document.pdf'),
margin: [20, 20, 20, 20],
autoPaging: 'text',
width: 170, // 有效内容区宽度(mm)
windowWidth: element.scrollWidth,
html2canvas: {
scale: 0.5, // 控制分辨率
letterRendering: true,
},
x: 10,
y: 10,
});
};
三、专业方案:Puppeteer(需后端配合)
javascript
javascript
// 前端
fetch('/generate-pdf', {
method: 'POST',
body: JSON.stringify({ html: document.documentElement.outerHTML }),
headers: { 'Content-Type': 'application/json' }
});
// Node.js后端
const puppeteer = require('puppeteer');
app.post('/generate-pdf', async (req, res) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(req.body.html);
const pdf = await page.pdf({
format: 'A4',
printBackground: true
});
await browser.close();
res.setHeader('Content-Type', 'application/pdf');
res.send(pdf);
});
四、样式优化要点
- 打印样式表
css
javascript
@media print {
@page { margin: 0; }
body { -webkit-print-color-adjust: exact; }
.no-print { display: none; }
}
- 强制分页
css
javascript
.page-break {
page-break-after: always;
break-after: page;
}
- 字体处理
css
javascript
@font-face {
font-family: 'PDFFont';
src: url('fonts/Songti.ttf') format('truetype');
}
body {
font-family: 'PDFFont', sans-serif;
}
五、方案对比
方案 | 优点 | 缺点 |
---|---|---|
html2canvas+jsPDF | 纯前端实现,视觉保真度高 | 文字变图片,文件体积较大 |
jsPDF HTML渲染 | 支持矢量文字,自动分页 | 兼容性问题,复杂布局易出错 |
Puppeteer | 完美还原,支持复杂CSS | 需要后端支持,消耗服务器资源 |
window.print() | 零依赖,简单快捷 | 样式控制能力弱,交互体验差 |
六、常见问题处理
- 内容截断
javascript
javascript
// 手动计算分页位置
const elementHeight = element.offsetHeight;
const pageHeight = 1122; // A4像素高度(96dpi)
if (elementHeight > pageHeight) {
// 插入分页符逻辑
}
- 图片跨域
html
javascript
<img crossorigin="anonymous" src="https://example.com/image.jpg">
运行 HTML
- 提升清晰度
javascript
javascript
html2canvas(element, {
scale: 3, // 最高3倍
dpi: 300,
letterRendering: true
});
根据具体需求选择方案:需要快速实现选择方案一,注重文字质量选方案二,企业级应用推荐方案三。