本文详细对比了三种将HTML页面转换为PDF的技术方案:wkhtmltopdf、Node.js结合Puppeteer以及纯前端的html2canvas与jspdf组合。通过实际代码示例与性能测试,分析了各方案在配置复杂度、生成质量及执行稳定性方面的差异,为开发者提供选型参考。
近期项目中遇到了将HTML页面转换为PDF报告的需求,经过调研并结合过往经验,总结出以下三种可行的技术方案。本文将重点展示基于这三种不同方案的Demo实现过程,并对它们进行对比分析。
方案选型
- html2canvas + jspdf
- wkhtmltopdf
- node + puppeteer
准备工作
为了模拟真实场景,我们利用ChatGPT生成了一个包含表格和ECharts柱状图的HTML报告模板。这种“文字+图表”的结构在实际项目中非常常见,因此该模板具有较好的测试参考价值。生成的HTML模板代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Report Page</title>
<!-- ECharts库 -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.page {
margin-bottom: 40px;
}
.chart {
width: 600px;
height: 400px;
margin-top: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th,
td {
text-align: left;
padding: 8px;
border-bottom: 1px solid #ddd;
}
</style>
</head>
<body>
<div class="page" id="page1">
<h2>Page 1 - Data and Chart</h2>
<table>
<tr>
<th>Item</th>
<th>Value</th>
</tr>
<tr>
<td>Item 1</td>
<td>100</td>
</tr>
<tr>
<td>Item 2</td>
<td>200</td>
</tr>
<!-- 更多列表数据 -->
</table>
<div id="chart1" class="chart"></div>
</div>
<div class="page" id="page2">
<table>
<tr>
<th>Item</th>
<th>Value</th>
</tr>
<tr>
<td>Item 1</td>
<td>100</td>
</tr>
<tr>
<td>Item 2</td>
<td>200</td>
</tr>
<!-- 更多列表数据 -->
</table>
<h2>Page 2 - Data and Chart</h2>
<!-- 类似的列表和图表占位符 -->
<div id="chart2" class="chart"></div>
</div>
<div class="page" id="page3">
<table>
<tr>
<th>Item</th>
<th>Value</th>
</tr>
<tr>
<td>Item 1</td>
<td>100</td>
</tr>
<tr>
<td>Item 2</td>
<td>200</td>
</tr>
<!-- 更多列表数据 -->
</table>
<h2>Page 3 - Data and Chart</h2>
<!-- 类似的列表和图表占位符 -->
<div id="chart3" class="chart"></div>
</div>
<script>
// ECharts 图表示例
var chart1 = echarts.init(document.getElementById('chart1'));
var option1 = {
title: {text: 'ECharts 示例 1'},
tooltip: {},
xAxis: {data: ['类别1', '类别2', '类别3', '类别4']},
yAxis: {},
series: [{type: 'bar', data: [5, 20, 36, 10]}]
};
chart1.setOption(option1);
// 为page2和page3重复上面的过程,设置不同的option配置
var chart2 = echarts.init(document.getElementById('chart2'));
chart2.setOption(option1);
var chart3 = echarts.init(document.getElementById('chart3'));
chart3.setOption(option1);
</script>
</body>
</html>
接下来,使用http-server在HTML文件所在目录下启动一个Web服务器。如果尚未安装http-server,可参考npm官方文档进行安装(www.npmjs.com/package/http-server)。
http-server . -p 9090
访问 http://127.0.0.1:9090/report.html,即可在浏览器中看到生成的报告模板页面,效果如下:

方案一:wkhtmltopdf
首先,前往wkhtmltopdf官网(wkhtmltopdf.org/downloads.html)下载对应操作系统的安装包并完成安装。
安装完成后,执行以下命令即可生成PDF文件:
wkhtmltopdf http://127.0.0.1:9090/report.html report.pdf
查看生成的PDF内容,显示正常,初步看来没有明显问题。

然而,实际报告通常包含多页内容。为了测试分页功能,我们在page1和page2元素后分别添加了一个特定的CSS类。
对应的CSS类定义如下:
.page-break-after {
page-break-after: always;
}
再次执行转换命令后,得到的PDF效果如下:

存在的问题
该方案偶尔会出现卡在某个进度不动的情况,具体原因尚不明确。

此外,执行时间存在不稳定性,有时快有时慢。
方案二:Node.js + Puppeteer
Puppeteer的安装过程较为简单,此处不再赘述,读者可自行查阅相关文档。安装完成后,我们同样利用ChatGPT生成了一段测试代码,如下所示:
const puppeteer = require('puppeteer');
async function savePageAsPDF(url, outputPath) {
// 启动浏览器
const browser = await puppeteer.launch();
// 打开新页面
const page = await browser.newPage();
// 导航到指定URL
await page.goto(url, { waitUntil: 'networkidle2' });
// 保存页面为PDF
await page.pdf({ path: outputPath, format: 'A4' });
// 关闭浏览器
await browser.close();
console.log(`PDF已保存到:${outputPath}`);
}
// 调用函数保存网页为PDF
savePageAsPDF('http://127.0.0.1:9090/report.html', 'report1.pdf').catch(console.error);
执行上述转换脚本后:
node index.js
生成的PDF内容如下,初步看来效果良好。

方案三:html2canvas + jspdf
首先,在HTML页面中引入html2canvas和jspdf的相关脚本库。
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.3.2/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.3.1/jspdf.umd.min.js"></script>
接着,添加一个下载按钮以及对应的转换函数逻辑。
<button onclick="convertToPDF()">Convert to PDF</button>
<script>
async function addPage(id, pdf) {
const element = document.getElementById(id);
// 使用 html2canvas 渲染指定元素
const canvas = await html2canvas(element, {scale: 2});
const imgData = canvas.toDataURL('image/png');
// 使用 jsPDF 创建PDF文档
const imgProps = pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
// const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
const pdfHeight = (imgProps.height / imgProps.width) * pdfWidth;
// const pdfHeight = pdf.internal.pageSize.getHeight();
console.log(imgProps.width, pdfWidth, pdfHeight, pdf.internal.pageSize.getHeight());
pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight, 'NONE', 'FAST');
}
async function convertToPDF() {
const pdf = new window.jspdf.jsPDF();
await addPage('page1', pdf);
pdf.addPage();
await addPage('page2', pdf);
pdf.addPage();
await addPage('page3', pdf);
pdf.save('converted.pdf');
}
</script>
访问页面后,点击按钮即可下载PDF文件,最终内容如下:

方案对比
wkhtmltopdf:依赖后端环境,配置相对灵活,但执行速度表现不稳定。
Puppeteer:同样依赖后端环境,生成的PDF准确度较高,质量表现良好。
html2canvas + jspdf:纯前端实现方案,依赖较少,适合轻量级场景。
以上即为JavaScript实现HTML转PDF的三种方法详解。如需了解更多关于JavaScript HTML转PDF的资料,请持续关注本站其他相关文章!