该脚本允许您直接在用户浏览器上将网页或部分网页生成为可编辑、非图片式、可打印的矢量 PDF。支持分页,最多可以生成上数千页的 PDF 文件。
该脚本基于 html2canvas 和 jspdf。与以往将
HTML 页面通过 html2canvas 渲染为图片,再通过 jspdf 将图片生成 PDF
文件不同,该脚本通过读取 DOM 和应用于元素的不同样式,改造了
html2canvas 的 canvas-renderer 文件,调用 jspdf 的方法生成 PDF 文件。
| 功能 | 状态 | 说明 |
|---|---|---|
| 分页 | ✅ | 支持 PDF 分页渲染,可生成数千页的 PDF 文件 |
| 文本渲染 | ✅ | 支持基础文本内容渲染,font-family, font-size, font-style, font-variant, color 等,支持文字描边,不支持文字阴影 |
| 图片渲染 | ✅ | 支持网络图片,base64 图片,svg 图片 |
| 边框 | ✅ | 支持 border-width, border-color, border-style, border-radius,暂时只实现了实线边框 |
| 背景 | ✅ | 支持背景颜色,背景图片,背景渐变 |
| canvas | ✅ | 支持渲染 canvas |
| svg | ✅ | 支持渲染 svg |
| 阴影渲染 | ✅ | 使用 foreignObjectRendering,支持边框阴影渲染 |
| 渐变渲染 | ✅ | 使用 foreignObjectRendering,支持背景渐变渲染 |
| iframe | ❌ | 暂不支持渲染 iframe |
dompdf 库使用 Promise 并期望它们在全局上下文中可用。如果您希望支持不原生支持 Promise 的较旧浏览器,请在引入 dompdf 之前包含一个 polyfill。
npm install dompdf.js --save
CDN 引入:
<script src="https://cdn.jsdelivr.net/npm/dompdf.js@latest/dist/dompdf.js"></script>
import dompdf from "dompdf.js";
dompdf(document.querySelector("#capture"), options)
.then((blob) => {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "example.pdf";
document.body.appendChild(a);
a.click();
})
.catch((err) => {
console.error(err);
});
默认情况下,dompdf 会将整个文档渲染到单页中。您可以通过设置
pagination 选项为 true 来开启分页渲染。通过
pageConfig
字段自定义页眉页脚的尺寸、内容、字体颜色/大小、位置等信息。
<div id="capture" style="width: 794px"></div>
import dompdf from "dompdf.js";
dompdf(document.querySelector("#capture"), {
pagination: true,
format: "a4",
pageConfig: {
header: {
content: "这是页眉",
height: 50,
contentColor: "#333333",
contentFontSize: 12,
contentPosition: "center",
padding: [0, 0, 0, 0],
},
footer: {
content: "第${currentPage}页/共${totalPages}页",
height: 50,
contentColor: "#333333",
contentFontSize: 12,
contentPosition: "center",
padding: [0, 0, 0, 0],
},
},
})
.then((blob) => {
// ... 下载逻辑
});
如果您不希望某个容器在分页时被拆分,请为该元素添加
divisionDisable 属性,跨页时它会整体移至下一页。
| 参数名 | 必传 | 默认值 | 类型 | 说明 |
|---|---|---|---|---|
| useCORS | 否 | false | boolean | 允许跨域资源(需服务端 CORS 配置) |
| backgroundColor | 否 | 自动解析/白色 | string | null | 覆盖页面背景色;传 null 生成透明背景 |
| fontConfig | 否 | - | object | 非英文字体配置 |
| encryption | 否 | 空配置 | object | PDF 加密配置 |
| precision | 否 | 16 | number | 元素位置的精度 |
| compress | 否 | false | boolean | 是否压缩PDF |
| putOnlyUsedFonts | 否 | false | boolean | 仅将实际使用的字体嵌入 PDF |
| pagination | 否 | false | boolean | 开启分页渲染 |
| format | 否 | 'a4' | string | 页面规格,支持 a0–a10、b0–b10、c0–c10、letter 等 |
| pageConfig | 否 | - | object | 页眉页脚配置 |
| 参数名 | 默认值 | 类型 | 说明 |
|---|---|---|---|
| header | 见下表 pageConfigOptions | object | 页眉设置 |
| footer | 见下表 pageConfigOptions | object | 页脚设置 |
| 参数名 | 默认值 | 类型 | 说明 |
|---|---|---|---|
| content | 页眉默认值为空,页脚默认值为 ${currentPage}/${totalPages} | string | 文本内容,支持 ${currentPage}、${totalPages},${currentPage}为当前页码,${totalPages}为总页码 |
| height | 50 | number | 区域高度(px) |
| contentPosition | 'center' | string | [number, number] | 文本位置枚举 center、centerLeft 、 centerRight、centerTop、 centerBottom、leftTop、 leftBottom、rightTop、rightBottom或坐标 [x,y] |
| contentColor | '#333333' | string | 文本颜色 |
| contentFontSize | 16 | number | 文本字号(px) |
| padding | [0,24,0,24] | [number, number, number, number] | 上/右/下/左内边距(px) |
| 字段 | 必传 | 默认值 | 类型 | 说明 |
|---|---|---|---|---|
| fontFamily | 是(启用自定义字体时) | '' | string | 字体家族名(与注入的 .ttf 同名) |
| fontBase64 | 是(启用自定义字体时) | '' | string | .ttf 的 Base64 字符串内容 |
由于 jspdf 只支持英文,所以其他语言会出现乱码的问题,需要导入对应的字体文件来解决,如果需要自定义字体,在 https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html 将字体 tff 文件转化成 base64 格式的 js 文件,中文字体推荐使用 SourceHanSansSC-Normal-Min-normal.js,体积较小。
在代码中引入该文件即可。
<script type="text/javascript" src="./SourceHanSansSC-Normal-Min-normal.js"></script>
<script>
dompdf(document.querySelector('#capture'), {
useCORS: true,
fontConfig: {
fontFamily: 'SourceHanSansSC-Normal-Min',
fontBase64: window.fontBase64
}
})
.then(function (blob) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'example.pdf';
document.body.appendChild(a);
a.click();
})
.catch(function (err) {
console.error(err);
});
</script>
在 dom 十分复杂,或者 pdf 无法绘制的情况(比如:复杂的表格,边框阴影,渐变等),可以考虑使用 foreignObjectRendering。
给要渲染的元素添加 foreignObjectRendering 属性,就可以通过 svg 的 foreignObject 将它渲染成一张背景图插入到 pdf 文件中。
但是,由于 foreignObject 元素的渲染依赖于浏览器的实现,因此在不同的浏览器中可能会有不同的表现。
所以,在使用 foreignObjectRendering 时,需要注意以下事项:
示例:
<div style="width: 100px;height: 100px;" foreignObjectRendering>
<div
style="width: 50px;height: 50px;border: 1px solid #000;box-shadow: 2px 2px 5px rgba(0,0,0,0.3);background: linear-gradient(45deg, #ff6b6b, #4ecdc4);"
>
这是一个div元素
</div>
</div>
该库应该可以在以下浏览器上正常工作(需要
Promise polyfill):