1. 背景
开发过程中,有时候会希望将页面的内容导出为pdf,第一反应是使用jsPDF与html2canvas结合,然后浏览器直接生成PDF,但通过这种方式生成的pdf会有很多问题。比如
- 字体缺失
- pdf页眉页脚只能实现非常简单的配置
- 内容被裁减,需要做大量的js处理才能实现
- 跨域资源加载失败
- pdf清晰度极差,样式与页面中的样式差别较大
那么有没有更好用的方式能够规避这些问题,那就是pdfmake
2. 介绍
Pdfmake 是一个方便的 JavaScript 库,既免费又开源,是简化在 Web 应用程序中创建 PDF 文档过程的绝佳工具。您可以通过定义文本、图像、表格等来声明 PDF 文档结构,并应用样式,pdfmake 将管理其余部分以创建具有所需视觉样式的 PDF
以下是 pdfmake 的一些主要功能:
- 创建 PDF: Pdfmake 使您能够从结构化数据创建 PDF 文档,从而轻松生成报告、发票、表格和其他类型的文档。
- 添加表格:Pdfmake 使您能够轻松地设计和将表格插入到您的 PDF 中,从而显示表格数据并保持结构化布局简单。
- 添加图像: Pdfmake 允许在您的 PDF 文档中包含图像,从而可以合并徽标、图形或照片以增强视觉吸引力。
- 添加密码: Pdfmake 支持为您的 PDF 添加密码保护,通过要求输入文档访问密码来帮助保护敏感信息。
3. 使用
1. 安装
yarn add pdfmake html-to-pdfmake # html-to-pdfmake用于将未知的html转化为pdf,使用场景为富文本编辑器
yarn add @types/html-to-pdfmake @types/pdfmake -D
2. 引用
import pdfMake from 'pdfmake/build/pdfmake';
import pdfFonts from 'pdfmake/build/vfs_fonts';
import htmlToPdfmake from 'html-to-pdfmake';
3. 定义pdf文档内容
const documentDefinition = {
pageSize: "LETTER", // 页面大小为 Letter
pageOrientation: "landscape", // 横向页面
pageMargins: [20, 35, 20, 15], // [left, top, right, bottom] 边距
header: {
columns: [
"模拟左页眉",
{
text: "页眉",
alignment: "center", // 文本位置
fontSize: 10, // 文本大小
color: "orange", // 文本颜色
margin: [0, 15, 0, 0]
},
{
text: "右页眉",
alignment: "right",
bold: true, // 加粗
}
],
},
footer: {
columns: [
"模拟左页脚",
{
text: "页脚",
alignment: "center", // 文本位置 fontSize: 10, // 文本大小
color: "orange", // 文本颜色
margin: [0, 15, 0, 0] }, // 边距
{
text: "右页脚",
alignment: "right",
bold: true, // 加粗
},
],
},
content: [ // pdf内容
{ table: // table使用
{
widths: [553, 180],
style: "titleCellStyle",
body: [
{
columns: [
{ svg: "svg", // 设置icon,页面中如果有全选的选中/未选中状态,也可使用svg实现 },
{
margin: [15, 10, 5, 10],
stack: [ // 将text转化为多行,同时可对每一行单独设置样式
{
text: "主标题",
style: "titleCellStyle"
},
{
text: "子标题",
style: "titleCellStyle", // 与配置中styles关联
},
],
}
]
}
]
}
}
],
styles: { // 设置统一的样式,content处通过style引用
titleCellStyle: {
lineHeight: 1.5,
bold: true,
}
},
background: [ // 设置水印,如果需要设置多水印,数组里可添加多个,改变坐标即可
{
work: {
text: "水印",
fontSize: 30,
bold: true,
color: "blue",
angle: -45, // 倾斜度
opacity: 0.3, // 透明度
italics: true, // 斜体
},
absolutePosition: { // 水印坐标
x: 100,
y: 100
}
}
]
};
4. 富文本处理
以上的文档只能实现已知的内容,对于富文本中的内容则需要通过
html-to-pdfmake实现
const html = htmlToPdfmake(HTMLElement, {
imagesByReference: true, // 图片
tableAutoSize: true, // 表格缩紧
ignoreStyles: ['font-family'], // 忽略样式
defaultStyles: {
h1: { // 设置h1标题对应的字体,其他标签对应的字体也可以在这设置
fontSize: 18,
bold: true,
marginBottom: 5
}
}
});
html中包括content与images两部分内容,其中item.content可通过stack渲染,内容追加到content中
{
stack: item.content
}
注意:pdf中的图片需要在image声明之后才可以引用, 意味着此时富文本中的images是无法直接显示的,需要在文档中声明之后才可以显示
// 将图片数组转为对象
for (const key in item.images) {
imagesObj[key] = item.images[key];
}
// 将图片映射到页面文档中
images: imagesObj,
注意:富文本图片显示成功之后,富文本中本来图片在一行的,存在换行,是因为图片会被每个stack包裹。
5. 完整的文档结构
{
pageSize: '',
pageOrientation: '',
pageMargins: [],
header: {
...
},
footer: {
...
},
content: [...],
styles: {
...
},
background: [...]
}
## 6. 导出pdf
```javascript
pdfMake.vfs = (pdfFonts as any).pdfMake.vfs; // 设置字体
const pdfDocGenerator = pdfMake.createPdf(documentDefinition); //创建 PDF 文档
pdfDocGenerator.download('filename.pdf'); // 下载 PDF 文件
pdfMake.createPdf(docDefinition).open(); // 在新窗口打开生成的PDF文件
pdfMake.createPdf(docDefinition).print(); // 直接调用浏览器打印功能打印