JavaScript实现html转pdf的三种方法详解

 更新时间:2024年02月23日 10:47:52   作者:cooljser  
近期项目需要实现将 html 页面转换成 pdf 报告的需求,经过一番调研以及结合过往经验,发现了三种技术方案,下面我们就来看看它们的具体实现步骤吧

近期项目需要实现将 html 页面转换成 pdf 报告的需求,经过一番调研以及结合过往经验,发现了有如下三种技术方案,本篇文章主要内容是基于这三种不同方案的 demo 实现及对比。

方案选型

  • html2canvas + jspdf
  • wkhtmltopdf
  • node + puppeteer

准备工作

利用 chatgpt 生成一个报告的 html 模板,每页包含了一个表格和一个由 echarts 生成的柱状图。实际项目中基本也是这样的内容,文字 + charts,所以用这个来测试具有一定的参考意义,生成的 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, 参考这里安装 www.npmjs.com/package/http-server)

http-server . -p 9090

访问 http://127.0.0.1:9090/report.html,即可看到对应的报告模板页面,如下:

wkhtmltopdf

到这里 wkhtmltopdf.org/downloads.html 下载系统对应版本的安装包,然后安装好

执行如下命令,即可生成 pdf

wkhtmltopdf http://127.0.0.1:9090/report.html report.pdf

查看生成的 pdf 内容,能正常显示,看起来也没啥问题

实际报告肯定是有多页的,接下来我们尝试一下看看如何分页。在 page1 和 page2 元素后分别加入一个

元素,对应的 class 如下:

.page-break-after {
	page-break-after: always;
}

然后再次执行转换命令,得到的 pdf 如下:

问题

偶尔会卡在某个进度不动,不知道为啥

执行时间不稳定,时快时慢

putteteer

安装就不多说明了,自行 google。安装好后,同样让 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

引入 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,依赖后端,配置比较灵活,但是速度好像不稳定

pupeteer,依赖后端,生成的 pdf 比较准确,质量也还可以

html2canvas + jspdf,纯前端实现,依赖少

以上就是JavaScript实现html转pdf的三种方法详解的详细内容,更多关于JavaScript html转pdf的资料请关注脚本之家其它相关文章!

相关文章

  • js实现文本框支持加减运算的方法

    js实现文本框支持加减运算的方法

    这篇文章主要介绍了js实现文本框支持加减运算的方法,可实现文本框输入加减运算式同时右侧实时显示对应计算结果的功能,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-08-08
  • Bootstrap框架动态生成Web页面文章内目录的方法

    Bootstrap框架动态生成Web页面文章内目录的方法

    这篇文章主要介绍了Bootstrap框架动态生成Web页面文章内目录的方法,利用Bootstrap中的Affix和ScrollSpy插件便可以实现,需要的朋友可以参考下
    2016-05-05
  • 利用js编写响应式侧边栏

    利用js编写响应式侧边栏

    这篇文章主要为大家详细介绍了利用js编写响应式侧边栏的相关代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • PHP 实现一种多文件上传的方法

    PHP 实现一种多文件上传的方法

    之前做项目的时候在实现表单中file类型input选择多图片时有很多种实现方法,今天小编给大家分享基于php实现一种多文件上传的方法,需要的朋友参考下吧
    2017-09-09
  • 微信小程序使用gitee进行版本管理

    微信小程序使用gitee进行版本管理

    这篇文章主要介绍了微信小程序使用gitee进行版本管理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • webpack4.x CommonJS模块化浅析

    webpack4.x CommonJS模块化浅析

    这篇文章主要介绍了webpack4.x CommonJS模块化浅析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • laydate 显示结束时间不小于开始时间的实例

    laydate 显示结束时间不小于开始时间的实例

    下面小编就为大家带来一篇laydate 显示结束时间不小于开始时间的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 用javascript获取地址栏参数

    用javascript获取地址栏参数

    用javascript获取地址栏参数...
    2006-12-12
  • 微信小程序中网络请求缓存的解决方法

    微信小程序中网络请求缓存的解决方法

    这篇文章主要给大家介绍了关于微信小程序中网络请求缓存的解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用微信小程序具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-12-12
  • window.open打开新页面失效解决方案

    window.open打开新页面失效解决方案

    这篇文章主要给大家介绍了关于window.open打开新页面失效的解决方案,移动端和PC端全部通过window.open()来跳转页面窗口,文中给出了详细的解决方案,需要的朋友可以参考下
    2023-07-07

最新评论