【jspdf】前端html生成pdf

615 阅读4分钟

前言

在上一篇文章中提到的通过html2canvas和jsPDF导出PDF的方法中,成功解决了文字和图片截断的问题。然而,在测试人员测试过程中,提出了新的问题:当导出的PDF页数过多时(大于100页时出现这种情况),出现了空白页的问题。经过多次尝试和判断,发现这是由于浏览器对Canvas高度的限制所导致的。 要解决这个问题,主要思路是通过将Canvas拆分后再进行导出。然而,这种方法实施起来相当繁琐,因此我决定寻找一种更为简便的方法来从根本上解决这个问题。本文将介绍一种新的导出PDF的方法,并解释一些常见问题及其解决方案。

目标

  • 使用 jsPDF 直接生成 PDF 文档。
  • 设置 PDF 的标题、页面内容、表格等。
  • 支持文本、表格、页码等元素的添加。

1. 安装 jsPDF

首先,你需要安装 jsPDF 库。如果你是通过 npm 管理项目的,可以运行以下命令:

npm install jspdf

或者在 HTML 文件中通过 CDN 引入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>

2. 创建一个简单的 PDF 文件

import jsPDF from 'jspdf';
import 'jspdf-autotable';

// 定义页面边距
const PAGE_MARGIN = 10;

// 创建一个新的PDF文档实例
const doc = new jsPDF()
const text = "Page 1 - Hello, World!";
// 添加第一页内容
doc.text(text, PAGE_MARGIN, PAGE_MARGIN);
// 获取文本高度
const textHeight = doc.getTextDimensions(text).h;
// 添加表格
const data = [
  ["Index", "Name", "Age", "City"],
  [1, "小梦", 18, "杭州"],
  [2, "小雨", 18, "杭州"],
  [3, "大婷", 18, "上海"],
];
 const numColumns = data[0].length;//获取表格字段长度
const columnWidth = (doc.internal.pageSize.width - PAGE_MARGIN * 2) / numColumns;//每个单元格的宽度
doc.autoTable({
  startY: textHeight + PAGE_MARGIN, // 开始渲染表格的高度位置
  head: [data[0]],//head根据需要可以不写的
  body: data.slice(1),
  margin: { top: PAGE_MARGIN }, // 上边距
  styles: {
        fontSize: 16,
        fontStyle: "bold",
        font: "SourceHanSansCN-Normal",//设置字体 否则中文会乱码
        background: "#fff",
        halign: "left",
        overflow: "linebreak",//设置换行,可以解决一行文本太长,文字重叠的问题
        columnWidth,
        textColor: [0, 0, 0],
        fillColor: "#fff"
    },
});

// 添加第二页内容
doc.addPage();
doc.text("Page 2 - Hello, World2!.", PAGE_MARGIN, PAGE_MARGIN);

// 保存PDF文件
doc.save("example.pdf");

3.根据接口数据动态分页处理

import jsPDF from 'jspdf';
import 'jspdf-autotable';

const exportPDF = () => {
  const doc = new jsPDF();
  // 定义页面边距
  const PAGE_MARGIN = 10;
  // 页面宽高
  const width = doc.internal.pageSize.getWidth();
  const height = doc.internal.pageSize.getHeight();
  // 内容最大宽高
  const pdfCentWidth = width - PAGE_MARGIN * 2;
  const pdfCentHeight = height - PAGE_MARGIN * 2;
  let startY = PAGE_MARGIN;

  // 计算文本高度,并在需要时分页(假设获取的数据如下)
  const text = '测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本';
  // splitTextToSize方法将文本分割为适合页面宽度的行
  const splitText = doc.splitTextToSize(text, pdfCentWidth);
  splitText.forEach((line) => {
  // getTextDimensions计算每一行文本行高
    const lineHeight = doc.getTextDimensions(line).h;
    // 如果当前起点大于最大内容高度,则新增一页,并且初始化startY
    if (startY + lineHeight > pdfCentHeight) {
      doc.addPage();
      startY = PAGE_MARGIN;
    }
    doc.text(line, PAGE_MARGIN, startY + lineHeight / 2);
    startY += lineHeight;
  });

4.每页添加页码

const pageWidth = doc.internal.pageSize.width;
const pageHeight = doc.internal.pageSize.height;
const totalPages = doc.internal.pages.length - 1;

for (let i = 1; i <= totalPages; i++) {
    doc.setPage(i);
    doc.text(` ${i} / ${totalPages}`, pageWidth / 2, pageHeight - 10, {align: "center"});
}

5.解决中文乱码

在使用jspdf导出的时候出现中文,会出现乱码的情况。可以通过添加中文字体库来解决。

5.1 可以下载思源黑体、简体、中文全套TTF格式,下载地址:gitcode.com/open-source…

image.png 5.2 转换字体,打开jspdf提供的在线字体转化网站:https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html

image.png