JavaScript实现HTML转PDF的三种方案:wkhtmltopdf、Puppeteer与html2canvas对比

作者:小圆点

时间:2026-10-31

浏览:650

本文详细对比了三种将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的资料,请持续关注本站其他相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章