html生成pdf的jspdf和html2pdf使用

有些场景需要生成pdf文件,然而多数情况下对pdf文件的格式内容都有要求,因此研究下由html生成pdf的组件,找到了jspdf和html2pdf这两种,而html2pdf是基于jspdf的。

jspdf  2.5.1       html2canvas 1.4.1       html2pdf.js v0.9.3

先使用bootstrap5做个demo页面

查看代码
 <!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>jspdf</title>
    <link href="./plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <script src="./plugins/jquery/jquery-1.9.1.js"></script>
    <script src="./plugins/jspdf/dist/jspdf.umd.min.js"></script>
    <script src="./plugins/html2canvas.min.js"></script>
    <script src="./plugins/jspdf/msyh-normal.js"></script>
    <script src="./plugins/html2pdf.bundle.min.js"></script>
    <script src="./plugins/jsPDF-AutoTable-master/dist/jspdf.plugin.autotable.js"></script>
    <style>
      body * {
        font-family: "msyh";
        letter-spacing: 0.01px; /*解决jspdf的英文字母间隔问题  */
      }
      tr {
        height: 3rem;
      }
    </style>
  </head>
 <!-- body的宽度是为了适配pdf文件 -->
  <body style="width: 158mm">
    <div id="myExportArea" class="container pt-2">
      <div style="page-break-inside: avoid">
        <h1>H1标题</h1>
        <h2>H2标题</h2>
        <h3>H3标题</h3>
        <h4>H4标题</h4>
        <h5>H5标题</h5>
        <h6>H6标题</h6>
      </div>
      <table style="border: 1px solid black; width: 100%; page-break-inside: avoid" class="table table-bordered" id="table1">
        <tr class="text-center">
          <th scope="col">中文</th>
          <th scope="col">First</th>
          <th scope="col">Last</th>
          <th scope="col">Handle</th>
        </tr>
        <tr>
          <th scope="row">1</th>
          <td style="background-color: #f5da55">Mark</td>
          <td>Otto</td>
          <td>mdo</td>
        </tr>
        <tr>
          <th scope="row">2</th>
          <td>Jacob</td>
          <td>Thornton</td>
          <td>fat</td>
        </tr>
        <tr>
          <th scope="row">3</th>
          <td colspan="2">Larry the Bird</td>
          <td>twitter</td>
        </tr>
      </table>
      <div class="row g-1 mt-2" id="exportArea" style="page-break-inside: avoid">
        <div class="col-6">
          <div class="card">
            <img src="./images/1.jpg" class="card-img-top" />
            <div class="card-body">
              <h5 class="card-title">明天</h5>
              <p class="card-text">明天,又是新的一天。</p>
            </div>
          </div>
        </div>
        <div class="col-6">
          <div class="card">
            <img src="./images/1.jpg" class="card-img-top" />
            <div class="card-body">
              <h5 class="card-title">明天</h5>
              <p class="card-text">明天,又是新的一天。</p>
            </div>
          </div>
        </div>
      </div>
      <div class="row g-1 mt-2" id="exportArea" style="page-break-inside: avoid">
        <div class="col-6">
          <div class="card">
            <img src="./images/1.jpg" class="card-img-top" />
            <div class="card-body">
              <h5 class="card-title">明天</h5>
              <p class="card-text">明天,又是新的一天。</p>
            </div>
          </div>
        </div>
        <div class="col-6">
          <div class="card">
            <img src="./images/1.jpg" class="card-img-top" />
            <div class="card-body">
              <h5 class="card-title">明天</h5>
              <p class="card-text">明天,又是新的一天。</p>
            </div>
          </div>
        </div>
      </div>
      <table style="border: 1px solid black; width: 100%; page-break-inside: avoid" class="table table-bordered mt-2" id="table2">
        <tr class="text-center">
          <th scope="col">中文</th>
          <th scope="col">First</th>
          <th scope="col">Last</th>
          <th scope="col">Handle</th>
        </tr>
        <tr>
          <th scope="row">1</th>
          <td style="background-color: #f5da55">Mark</td>
          <td>Otto</td>
          <td>mdo</td>
        </tr>
        <tr>
          <th scope="row">2</th>
          <td>Jacob</td>
          <td>Thornton</td>
          <td>fat</td>
        </tr>
        <tr>
          <th scope="row">3</th>
          <td colspan="2">Larry the Bird</td>
          <td>twitter</td>
        </tr>
      </table>
      <table style="border: 1px solid black; width: 100%; page-break-inside: avoid" class="table table-bordered mt-2" id="table3">
        <tr class="text-center">
          <th scope="col">中文</th>
          <th scope="col">First</th>
          <th scope="col">Last</th>
          <th scope="col">Handle</th>
        </tr>
        <tr>
          <th scope="row">1</th>
          <td style="background-color: #f5da55">Mark</td>
          <td>Otto</td>
          <td>mdo</td>
        </tr>
        <tr>
          <th scope="row">2</th>
          <td>Jacob</td>
          <td>Thornton</td>
          <td>fat</td>
        </tr>
        <tr>
          <th scope="row">3</th>
          <td colspan="2">Larry the Bird</td>
          <td>twitter</td>
        </tr>
      </table>
    </div>
    <div style="margin-top: 3rem">
      <button type="button" class="btn btn-primary mb-2" onclick="testJsPdf('myExportArea')">jspdf downloadPdf</button>
      <button type="button" class="btn btn-primary mb-2" onclick="testJsPdfAutoTable('myExportArea')">jspdf AutoTable downloadPdf</button>
      <button type="button" class="btn btn-primary mb-2" onclick="testHtml2Pdf('myExportArea')">html2pdf downloadPdf</button>
      <button type="button" class="btn btn-primary mb-2" onclick="testHtml2Canvas('myExportArea')">exportPdf</button>
    </div>
  </body>
</html>

 显示如下:

下面看下html转换成pdf的css样式支持效果:

jspdf

 <button type="button" class="btn btn-primary mb-2" onclick="testJsPdf('myExportArea')">jspdf downloadPdf</button>
 <button type="button" class="btn btn-primary mb-2" onclick="testJsPdfAutoTable('myExportArea')">jspdf AutoTable downloadPdf</button>
<script>
    function testJsPdf(domId) {
      // const  doc = new jspdf.jsPDF("landscape", "pt", "a4"); // 170mm宽度
      const doc = new jspdf.jsPDF("portrait", "pt", "a4"); //宽度 158mm或者37.5rem
      doc.setFont("msyh");
      doc.html(document.getElementById(domId), {
        callback: function (doc) {
          const pageCount = doc.internal.getNumberOfPages();
          // for (let i = pageCount; i > 1; i--) {
          //   doc.deletePage(i);
          // }
          console.log(pageCount);
          // doc.save("test.pdf"); //下载pdf
          window.open(doc.output("bloburl")); //预览pdf
        },
      });
    }
    function testJsPdfAutoTable(domId) {
      const doc = new jspdf.jsPDF("portrait", "pt", "a4");
      doc.setFont("msyh");
      doc.autoTable({ html: "#table1", styles: { font: "msyh", fontStyle: "normal" }, useCss: true });
      doc.autoTable({ html: "#table2", styles: { font: "msyh", fontStyle: "normal" }, useCss: true });
      doc.autoTable({ html: "#table3", styles: { font: "msyh", fontStyle: "normal" }, useCss: true });
      const beginY = doc.lastAutoTable.finalY;
      doc.html(document.getElementById(domId), {
        callback: function (doc) {
          const pageCount = doc.internal.getNumberOfPages();
          console.log(pageCount);
          // doc.save("test.pdf"); //下载pdf
          window.open(doc.output("bloburl")); //预览pdf
        },
      });
    }
   
</script>

看着使用和不使用 jsPDF-AutoTable 效果差不多,css样式  page-break-inside: avoid 未生效,文本可选中。

html2pdf

 <button type="button" class="btn btn-primary mb-2" onclick="testHtml2Pdf('myExportArea')">html2pdf downloadPdf</button>
<script>
    function testHtml2Pdf(domId) {
      const element = document.getElementById(domId);
      const opt = {
        margin: 0,
        filename: "myfile.pdf",
        image: { type: "jpeg", quality: 0.98 },
        html2canvas: { dpi: 192, scale: 2, letterRendering: true },
        jsPDF: { unit: "pt", format: "a4", orientation: "portrait" },
        pagebreak: { mode: ["avoid-all"] },
      };
      html2pdf().set(opt).from(element).save();

      // const  worker = html2pdf();
      // for (let i = 0; i < pages.length; i++) {
      //   console.log(pages[i]);
      //   worker = worker
      //     .set(opt)
      //     .from(pages[i])
      //     .toContainer()
      //     .toCanvas()
      //     .toPdf()
      //     .get("pdf")
      //     .then((pdf) => {
      //       if (i < pages.length - 1) {
      //         pdf.addPage();
      //       }
      //     });
      // }
      // worker.save();
    }
</script>

css样式  page-break-inside: avoid 生效,避免了内部截断,然文本不可选中,为图片格式。

html2canvas+jspdf

  <button type="button" class="btn btn-primary mb-2" onclick="testHtml2Canvas('myExportArea')">exportPdf</button>
<script>
      
    function testHtml2Canvas(domId) {
      html2canvas(document.getElementById(domId), { scale: 2 }).then((canvas) => {
        const contentWidth = canvas.width;
        const contentHeight = canvas.height;

        //a4纸的尺寸[595,842]
        const a4_width = 595;
        const a4_height = 842;

        //单页换算成A4纸的页面高度;
        const pageHeight = (contentWidth / a4_width) * a4_height;
        //未生成pdf的页面高度
        let leftHeight = contentHeight;
        //pdf页面偏移
        let position = 0;

        //html页面生成的canvas在pdf中图片的宽高
        const imgWidth = a4_width;
        const imgHeight = (imgWidth / contentWidth) * contentHeight;

        const pageData = canvas.toDataURL("image/jpeg", 1.0);
        const pdf = new jspdf.jsPDF("p", "pt", "a4");
        //当内容未超过pdf一页显示的范围,无需分页
        if (leftHeight < pageHeight) {
          pdf.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
        } else {
          while (leftHeight > 0) {
            pdf.addImage(pageData, "JPEG", 0, position, imgWidth, imgHeight);
            leftHeight -= pageHeight;
            position -= a4_height;
            //避免添加空白页
            if (leftHeight > 0) {
              pdf.addPage();
            }
          }
        }
        let targetPage = pdf.internal.getNumberOfPages();
        // pdf.save("xxxx.pdf");
        window.open(pdf.output("bloburl")); //预览pdf
      });
    }
</script>

生成pdf为图片格式,不支持css样式  page-break-inside: avoid

posted @   carol2014  阅读(840)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示