翼度科技»论坛 编程开发 JavaScript 查看内容

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

9

主题

9

帖子

27

积分

新手上路

Rank: 1

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

方案选型


  • html2canvas + jspdf
  • wkhtmltopdf
  • node + puppeteer

准备工作

利用 chatgpt 生成一个报告的 html 模板,每页包含了一个表格和一个由 echarts 生成的柱状图。实际项目中基本也是这样的内容,文字 + charts,所以用这个来测试具有一定的参考意义,生成的 html 模板如下:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.   <head>
  4.     <meta charset="UTF-8" />
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6.     <title>Report Page</title>
  7.     <!-- ECharts库 -->
  8.     <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
  9.     <style>
  10.       body {
  11.         font-family: Arial, sans-serif;
  12.         margin: 20px;
  13.       }
  14.       .page {
  15.         margin-bottom: 40px;
  16.       }
  17.       .chart {
  18.         width: 600px;
  19.         height: 400px;
  20.         margin-top: 20px;
  21.       }
  22.       table {
  23.         width: 100%;
  24.         border-collapse: collapse;
  25.       }
  26.       th,
  27.       td {
  28.         text-align: left;
  29.         padding: 8px;
  30.         border-bottom: 1px solid #ddd;
  31.       }
  32.     </style>
  33.   </head>
  34.   <body>
  35.     <div class="page" id="page1">
  36.       <h2>Page 1 - Data and Chart</h2>
  37.       <table>
  38.         <tr>
  39.           <th>Item</th>
  40.           <th>Value</th>
  41.         </tr>
  42.         <tr>
  43.           <td>Item 1</td>
  44.           <td>100</td>
  45.         </tr>
  46.         <tr>
  47.           <td>Item 2</td>
  48.           <td>200</td>
  49.         </tr>
  50.         <!-- 更多列表数据 -->
  51.       </table>
  52.       <div id="chart1" class="chart"></div>
  53.     </div>   

  54.     <div class="page" id="page2">
  55.       <table>
  56.         <tr>
  57.           <th>Item</th>
  58.           <th>Value</th>
  59.         </tr>
  60.         <tr>
  61.           <td>Item 1</td>
  62.           <td>100</td>
  63.         </tr>
  64.         <tr>
  65.           <td>Item 2</td>
  66.           <td>200</td>
  67.         </tr>
  68.         <!-- 更多列表数据 -->
  69.       </table>
  70.       <h2>Page 2 - Data and Chart</h2>
  71.       <!-- 类似的列表和图表占位符 -->
  72.       <div id="chart2" class="chart"></div>
  73.     </div>   

  74.     <div class="page" id="page3">
  75.       <table>
  76.         <tr>
  77.           <th>Item</th>
  78.           <th>Value</th>
  79.         </tr>
  80.         <tr>
  81.           <td>Item 1</td>
  82.           <td>100</td>
  83.         </tr>
  84.         <tr>
  85.           <td>Item 2</td>
  86.           <td>200</td>
  87.         </tr>
  88.         <!-- 更多列表数据 -->
  89.       </table>
  90.       <h2>Page 3 - Data and Chart</h2>
  91.       <!-- 类似的列表和图表占位符 -->
  92.       <div id="chart3" class="chart"></div>
  93.     </div>

  94.     <script>
  95.       // ECharts 图表示例
  96.       var chart1 = echarts.init(document.getElementById('chart1'));
  97.       var option1 = {
  98.         title: {text: 'ECharts 示例 1'},
  99.         tooltip: {},
  100.         xAxis: {data: ['类别1', '类别2', '类别3', '类别4']},
  101.         yAxis: {},
  102.         series: [{type: 'bar', data: [5, 20, 36, 10]}]
  103.       };
  104.       chart1.setOption(option1);

  105.       // 为page2和page3重复上面的过程,设置不同的option配置
  106.       var chart2 = echarts.init(document.getElementById('chart2'));
  107.       chart2.setOption(option1);
  108.       var chart3 = echarts.init(document.getElementById('chart3'));
  109.       chart3.setOption(option1);
  110.     </script>
  111.   </body>
  112. </html>
复制代码
使用 http-server 在 html 页面目录下启动一个 web 服务器(没有 http-server, 参考这里安装 www.npmjs.com/package/http-server)
  1. http-server . -p 9090
复制代码
访问
  1. http://127.0.0.1:9090/report.html
复制代码
,即可看到对应的报告模板页面,如下:


wkhtmltopdf

到这里 wkhtmltopdf.org/downloads.html 下载系统对应版本的安装包,然后安装好
执行如下命令,即可生成 pdf
  1. wkhtmltopdf http://127.0.0.1:9090/report.html report.pdf
复制代码
查看生成的 pdf 内容,能正常显示,看起来也没啥问题

实际报告肯定是有多页的,接下来我们尝试一下看看如何分页。在 page1 和 page2 元素后分别加入一个
元素,对应的 class 如下:
  1. .page-break-after {
  2.         page-break-after: always;
  3. }
复制代码
然后再次执行转换命令,得到的 pdf 如下:

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

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

putteteer

安装就不多说明了,自行 google。安装好后,同样让 chatgpt 生成一段测试的代码,如下:
  1. const puppeteer = require('puppeteer');

  2. async function savePageAsPDF(url, outputPath) {
  3.   // 启动浏览器
  4.   const browser = await puppeteer.launch();
  5.   // 打开新页面
  6.   const page = await browser.newPage();
  7.   // 导航到指定URL
  8.   await page.goto(url, { waitUntil: 'networkidle2' });
  9.   // 保存页面为PDF
  10.   await page.pdf({ path: outputPath, format: 'A4' });
  11.   // 关闭浏览器
  12.   await browser.close();
  13.   console.log(`PDF已保存到:${outputPath}`);
  14. }

  15. // 调用函数保存网页为PDF
  16. savePageAsPDF('http://127.0.0.1:9090/report.html', 'report1.pdf').catch(console.error);
复制代码
执行转换脚本
  1. node index.js
复制代码
得到的 pdf 内容如下,看起来也没啥问题


html2canvas + jspdf

引入 html2canvas 和 jspdf 相关脚本
  1. <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.3.2/html2canvas.min.js"></script>
  2. <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.3.1/jspdf.umd.min.js"></script>
复制代码
添加下载按钮及转换函数
  1. <button onclick="convertToPDF()">Convert to PDF</button>

  2. <script>
  3.                 async function addPage(id, pdf) {
  4.                         const element = document.getElementById(id);

  5.                         // 使用 html2canvas 渲染指定元素
  6.                         const canvas = await html2canvas(element, {scale: 2});
  7.                         const imgData = canvas.toDataURL('image/png');

  8.                         // 使用 jsPDF 创建PDF文档
  9.                         const imgProps = pdf.getImageProperties(imgData);
  10.                         const pdfWidth = pdf.internal.pageSize.getWidth();
  11.                         // const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
  12.                         const pdfHeight = (imgProps.height / imgProps.width) * pdfWidth;
  13.                         // const pdfHeight = pdf.internal.pageSize.getHeight();
  14.                         console.log(imgProps.width, pdfWidth, pdfHeight, pdf.internal.pageSize.getHeight());
  15.                         pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight, 'NONE', 'FAST');
  16.                 }

  17.                 async function convertToPDF() {
  18.                         const pdf = new window.jspdf.jsPDF();

  19.                         await addPage('page1', pdf);
  20.                         pdf.addPage();
  21.                         await addPage('page2', pdf);
  22.                         pdf.addPage();
  23.                         await addPage('page3', pdf);

  24.                         pdf.save('converted.pdf');
  25.                 }
  26. </script>
复制代码
访问页面,点击按钮即可下载 pdf 了,内容如下:


方案对比

wkhtmltopdf,依赖后端,配置比较灵活,但是速度好像不稳定
pupeteer,依赖后端,生成的 pdf 比较准确,质量也还可以
html2canvas + jspdf,纯前端实现,依赖少
以上就是JavaScript实现html转pdf的三种方法详解的详细内容,更多关于JavaScript html转pdf的资料请关注脚本之家其它相关文章!

来源:https://www.jb51.net/javascript/316202km7.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具