前端生成 PDF 的解决方案:dompdf.js

2 阅读4分钟

dompdf.js

1. 文档概述

核心内容: dompdf.js - 一个前端生成 PDF 的解决方案,可在浏览器中直接将 HTML 生成为真正的、非图片式、可编辑的、高清晰度的 PDF 文件。

2. 资源链接

3. 技术方案对比分析

现有 PDF 生成方案对比

方案类型优点缺点
Puppeteer 等无头浏览器✅ 渲染效果与浏览器完全一致
✅ 支持 JavaScript 动态内容
❌ 资源消耗大(内存、CPU)
❌ 启动速度慢
❌ 并发处理能力有限
❌ 需要服务器环境
jsPDF/PDFKit✅ 纯前端实现,无服务器依赖
✅ 文件体积小
✅ 生成速度快
✅ 支持矢量图形
❌ 需要手动构建 PDF 结构
❌ 不支持复杂 HTML 布局
❌ 学习成本较高
❌ 样式支持有限
PDFMake✅ 纯前端解决方案
✅ 声明式 API,易于使用
✅ 支持表格、图表等
✅ 模板化程度高
❌ 不支持 HTML 直接转换
❌ 需要重新构建文档结构
❌ 样式定制能力有限
❌ 复杂布局实现困难
html2canvas + jsPDF✅ 实现简单
✅ 纯前端方案
✅ 所见即所得
❌ 生成图片式 PDF,无法编辑
❌ 文件体积大
❌ 清晰度不够
❌ 不支持文字选择
dompdf.js✅ 纯前端实现
✅ 快速上手,对代码入侵小
✅ 文件体积小
✅ 支持文字选择和编辑
✅ 矢量图形,清晰度高
❌ 部分 CSS 属性支持有限
❌ 复杂布局可能有差异
❌ 浏览器兼容性要求

4. dompdf.js 实现原理

技术基础

dompdf.js 基于 html2canvas + jsPDF 实现,但进行了关键性改造。

html2canvas 原理解析

  1. 遍历 DOM 树: 从指定 DOM 节点开始,递归遍历所有子节点,构建渲染队列
  2. 计算样式: 调用 window.getComputedStyle() 获取元素最终 CSS 属性值
  3. 构建渲染模型: 将 DOM 节点和计算样式包装成渲染对象
  4. 创建 Canvas 上下文: 在内存中创建 canvas 元素和 2D 渲染上下文
  5. 模拟浏览器绘制: 将 CSS 属性翻译成 Canvas API 调用

CSS 到 PDF 的 API 映射表

CSS 属性Canvas API 调用jsPDF API 调用
background-colorctx.fillStyle + ctx.fillRect()doc.setFillColor() + doc.rect(x, y, w, h, 'F')
borderctx.strokeStyle + ctx.strokeRect()doc.setDrawColor() + doc.rect(x, y, w, h, 'S')
color, font-family, font-sizectx.fillStyle, ctx.font + ctx.fillText()doc.setTextColor() + doc.setFont() + doc.text()
border-radius通过 arcTo()bezierCurveTo() 创建剪切路径doc.roundedRect() 或通过 doc.lines() 绘制圆角路径
imagectx.addImage()doc.addImage()

dompdf.js 的核心创新

将 html2canvas 最后一步的 Canvas API 调用替换为 jsPDF API 调用,实现从 DOM 到可编辑 PDF 的直接转换。

5. 功能支持情况

功能状态说明
文本渲染支持基础文本内容渲染,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
分页暂不支持分页

6. 【图片 Demo-1】foreignObjectRendering 功能演示

位置: 第6章节 - 使用 foreignObjectRendering 渲染复杂表格,边框阴影,渐变

Demo 描述

展示如何使用 foreignObjectRendering 属性处理复杂样式效果,包括边框阴影和渐变背景。

功能说明

  • 解决复杂表格、边框阴影、渐变等 PDF 难以直接绘制的情况
  • 通过 SVG 的 foreignObject 将元素渲染成背景图插入 PDF

代码片段

<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>

技术注意事项

  1. foreignObject 渲染依赖浏览器实现,不同浏览器表现可能不同
  2. IE 浏览器完全不支持,推荐在 Chrome、Firefox、Edge 中使用
  3. 生成的图片会导致 PDF 文件体积变大

7. 使用指南

安装

npm install dompdf.js --save

基础用法

import dompdf from "dompdf.js";

dompdf(document.querySelector("#capture"), {
  useCORS: true, //是否允许跨域
})
.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.log(err, "err");
});

字体支持

// 引入字体文件
<script type="text/javascript" src="./SourceHanSansSC-Normal-Min-normal.js"></script>;

dompdf(document.querySelector("#capture"), {
  useCORS: true, //是否允许跨域
  fontConfig: {
    fontFamily: "SourceHanSansSC-Normal-Min",
    fontBase64: window.fontBase64,
  },
})
.then(function (blob) {
  // 下载逻辑同上
});

字体配置说明

  • 需要将字体 TTF 文件转换为 base64 格式的 JS 文件
  • 推荐使用思源黑体中文字体,体积较小
  • 转换工具链接在文档中提供