发布时间:2022年1月23日
jsPDF 是一个基于 Javascript 的 pdf 文件生成库,目前在 npm 中每周的下载量在 60W 左右。
jsPDF 与 html2canvas 是目前比较主流的将前端页面转换成 PDF 的方案。
jsPDF-AutoText
是我个人开发的基于 jsPDF 的工具库,它通过对外暴露 AutoText Class
来提供服务。
用户在实例化该类时可以将需要创建的 PDF 文件的一些配置文件传入,后续通过持续化调用 AutoText
提供的 render
方法来即可自动化向 PDF 文件中添加文字,而不用关注文字的换行以及 PDF 文件分页等问题, 提交我们使用 jsPDF 时的体验。
最近的现场需求中客户要求可以从项目中导出对应的数据并整合成一个 PDF 文件,PDF 文件的内容包括了一页申请表以及一页文字描述,需要在页面上点击导出按钮时生成文件并自动下载至本地,供用户后续的打印及提交审批。
在调研需求的实现方案时,发现目前主流的方式是使用 jsPDF + html2canvas 的方案。这种方案需要我们先在页面上将要打印的内容渲染出来,然后使用 html2canvas 将 HTML 内容转成 Canvas,再将 Canvas 转成图片并通过 jsPDF 的 addImage
方法将图片添加到 PDF 文件中。
但是这个方案在后期进行实验的时候发现了一些问题,最终选择放弃使用 html2canvas,问题主要是以下几点:
后来通过在 github 上的查找,发现了一个叫做 jsPDF-AutoTable
的库,该库用于在 jsPDF 创建的 pdf 文件中创建一个复杂的表格。通过一些测试,该库完全可以满足我们的业务需求,那么现在的问题就剩下一个:第二页的文字描述如何解决。
其实 jsPDF 本身是提供手动添加文字内容的方法的,但这个方案在使用上有几个较重的心智负担:
基于以上问题,在梳理了文字渲染位置计算、换行、分页、缩进等情况后,根据这些写了一个 hook 方法,在项目中初始化传入一些 pdf 文件的信息,后续直接调用渲染文字方法可以毫无负担的创建我们想要的内容。
然后就有了这个库,与项目中不同的时,项目是基于 React Hook 编写的方法,并不能直接拿来作为通用方法使用,于是在原来的基础上做了一些调整:
Class
来替代原有的 Hook 方法实现,使得可以满足各个框架的使用。目前第一个版本已经发布到 npm 上,后续会持续添加新功能,如文字自适应居中、支持行内文字加粗/斜体、页面水印等功能。
使用方式其实很简单,首先惯例我们需要先添加相关依赖:
yarn add jspdf jspdf-autotext
然后在项目中直接引用即可,代码如下:
import jsPDF from 'jspdf';
import { AutoText as jsPDFAutoText } from 'jspdf-autotext';
// 创建 jsPDF 实例
const pdfFile = new jsPDF();
// 传入 jsPDF 实例,并使用默认的页面配置
const AutoText = new jsPDFAutoText({ pdfFile });
// 使用 render 方法渲染文字
const renderedPositions = AutoText.render([
{ text: '离骚', indent: 15 },
{ text: '屈原', indent: 15 },
'帝高阳之苗裔兮,朕皇考曰伯庸。',
'摄提贞于孟陬兮,惟庚寅吾以降。',
'皇览揆余初度兮,肇锡余以嘉名:名余曰正则兮,字余曰灵均。',
]);
// 添加新的页面
AutoText.addPage();
// 渲染新的文字
AutoText.render([
{ text: '赋得古原草送别', indent: 14 },
{ text: '白居易', indent: 15 },
'离离原上草,一岁一枯荣。',
'野火烧不尽,春风吹又生。',
'远芳侵古道,晴翠接荒城。',
'又送王孙去,萋萋满别情。',
]);
// 保存文件
pdfFile.save();
打开我们保存的文件就可以看到这样的内容
每一行不同的文字都会自动计算其渲染的坐标位置,不过目前缺少文字自动居中功能,需要使用缩进 indent
来手动居中,后续会优化这个体验。
以下默认值均是在 A4 纸情况下的默认,A4 纸的标注宽度为 210 毫米,高度为 297 毫米,所以以下值的单位也均为毫米
key | 名称 | 必填 / 默认值 | 数据类型 | 描述 |
---|---|---|---|---|
pdfFile | jsPDF 实例 | Y | jsPDF instance | - |
TEXT_LINE_MAX_WIDTH | 每一行文字的最大宽度,超过换行 | N / 190 | number | - |
INITIAL_POSITION_X | 每一行文字的起始 X 坐标 | N / 10 | number | 页面上文字的起点与纸张左侧的距离 |
INITIAL_POSITION_Y | 每一页文字的起始 Y 坐标 | N / 10 | number | 每页第一行文字顶部与纸张顶部的距离 |
EVERY_PAGE_MAX_HEIGHT | 每一页最高渲染多高的文字,超过换页 | N / 280 | number | - |
EVERY_INDENT_WIDTH | 每一个缩进的缩进量 | N / 5 | number | - |
EVERY_TEXT_LINE_HEIGHT | 每一行文字的行高 | N / 6 | number | 以宋体/10号字为基准,不同字体需要自行配置 |
目前 Render
方法接受两种类型的参数:配置对象或字符串,如果调用 Render
方法时传递的是数组则可以混合使用
// 纯字符串
AutoText.render('纯字符串调用');
// 配置对象调用
AutoText.render({ text: "配置对象调用", indent: 10 })
// 字符串数组
AutoText.render([
"字符串调用1",
"字符串调用2"
])
// 配置对象数组
AutoText.render([
{ text: "配置对象调用", indent: 10 }
{ text: "配置对象调用", indent: 10 }
])
// 混合调用
AutoText.render([
"混合调用纯字符串"
{ text: "配置对象调用", indent: 10 }
])
配置对象的配置格式有以下几个:
key | 名称 | 必填 / 默认值 | 数据类型 | 描述 |
---|---|---|---|---|
text | 文字内容 | Y | string | - |
indent | 缩进数量 | N | number | - |
…… | 请参照 jsPDF 中 Text Option选项 |
目前的 0.1.0 版本仅能支持一些最基本的文字渲染内容,后续会在以下方向做演进: