← dompdf.js Studio

uni-app 跨端项目集成 dompdf.js:PDF 生成指南

uni-app 一套代码同时发布到 H5、微信小程序和 App,给业务带来便利的同时,也让“导出 PDF”这类能力变得棘手:小程序没有浏览器 DOM,App 端环境又各不相同,很多 PDF 库在跨端场景下根本无法运行。dompdf.js 是纯前端 DOM 转 PDF 引擎,在 uni-app 的 H5 端可以直接渲染页面 DOM;小程序端虽然没有 DOM,但 addPage 支持 HTML 字符串输入,同样可以生成规范 PDF。本文梳理 H5、小程序、App 三种运行环境下的集成方案、代码示例与注意事项,帮助你按端选型、按需集成,用最少的代码实现三端可用的 PDF 导出能力,避免在选型上反复试错,把精力留给业务本身。

uni-app 跨端导出 PDF 的挑战

uni-app 的三种运行环境差异很大:H5 是标准浏览器,小程序是受限的 JS 运行时,App 端是 WebView 或原生渲染;PDF 库的选择必须考虑环境差异,不能只按浏览器场景选型,否则上线后才发现跑不通,返工成本很高,选型阶段就要想清楚,建议先用真实页面在各端做一轮最小验证,再决定技术方案,避免上线后返工,评估成本反而最低。

很多 PDF 库依赖浏览器 DOM,在小程序里根本无法运行;有的库输出质量差(位图截图、文字不可选),有的必须后端配合,跨端方案里很难做到一套代码统一,选型时要重点考察输入方式的灵活性,这是决定成败的关键,务必实测再定,用代表性页面在 H5、小程序各跑一遍,确认字体、分页、图片都正常,再进入正式开发。

好在“导出 PDF”的本质是“把结构化内容排版成文档”,dompdf.js 同时支持 DOM 节点和 HTML 字符串两种输入,为不同运行端提供了统一的接入方式,这是跨端集成的关键,也是与其他库最大的区别,值得优先考虑,实测兼容性也更好。

H5 端:直接渲染 DOM

H5 端就是标准浏览器环境,dompdf.js 可以像普通 Web 项目一样使用:拿到页面 DOM 节点传给 addPage,所见即所得地导出 PDF,体验最完整,所有能力(字体、图片、分页、页眉页脚)全部可用,开发调试也最方便,先跑通 H5 再扩展其他端,这也是官方推荐的最佳实践路径,先验证核心能力,再逐步覆盖小程序和 App 端,节奏更稳妥。

推荐使用条件编译(#ifdef H5)把导出逻辑限定在 H5 端,其他端走各自的方案;这样代码清晰、互不干扰,小程序端也不会因为引入 DOM 相关逻辑而报错,打包产物也更干净,发布到不同平台互不影响,这是 uni-app 工程的标准做法。

H5 端没有平台限制,适合管理后台、H5 报表、移动端报告这类对文档质量要求高的场景;导出速度、排版效果都与普通 Web 项目一致,用户在小程序里体验不到的完整能力,在 H5 端都能给到,功能完整度最高的端就是 H5。

代码示例:H5 端集成(条件编译)

条件编译注释在编译期生效:H5 包只包含浏览器代码,小程序包不会引入依赖 DOM 的导出逻辑,从根源上避免运行时错误,打包体积也更干净,同一份源码维护起来毫无负担,这是 uni-app 工程的常规写法,团队都会用,注意条件编译注释必须成对出现,漏掉 #endif 会导致代码丢失,写完后检查一遍构建产物。

页面里用 ref 标记导出区域(如 this.$refs.report),与普通 Vue 用法一致;接口数据加载完成后再触发导出,避免导出空白文档,必要时给按钮加 loading 状态提升体验,用户等待时也有反馈,导出成功后再给下载提示,失败时给出明确提示并支持重试,异常路径也处理到位。

小程序端可以先展示友好提示,引导用户使用“生成分享卡片”或后端生成 PDF 的兜底方案,保证功能在所有端都可用,只是实现路径不同;提示文案要写清楚,避免用户误以为功能缺失,客服压力也小,产品口碑更好,同时保留后端导出作为兜底方案,双保险更稳妥,覆盖极端情况。

// pages/report/report.vue
import { DomPDF } from 'dompdf.js';

export default {
  methods: {
    async exportPdf() {
      // #ifdef H5
      const pdf = new DomPDF();
      pdf.addPage(this.$refs.report, { format: 'A4', margin: '15mm' });
      pdf.save('report.pdf');
      // #endif
      // #ifdef MP-WEIXIN
      uni.showToast({ title: '小程序端请使用分享或后端导出', icon: 'none' });
      // #endif
    }
  }
}

小程序端:HTML 字符串方案

小程序没有浏览器 DOM,不能传节点,但 dompdf.js 的 addPage 接受 HTML 字符串:把数据拼成模板字符串即可生成 PDF,核心逻辑与 H5 端高度一致,复用成本低,模板还可以两边共用,一份模板双端生效,维护一套就够,只要数据字段对齐,两端导出效果几乎完全一致,设计师验收也省心。

小程序端受网络和包体积限制,建议把 dompdf.js 及其 WASM 文件放到 CDN 或由后端按需下发,避免挤占小程序主包体积,影响审核和加载速度;按需加载也能显著缩短冷启动时间,用户体验更好,包体红线也能守住。

文件下载与预览方面,小程序可以使用 wx.downloadFile 配合 wx.openDocument 打开 PDF 预览,或者引导用户通过邮件、网盘等渠道获取文件,满足移动端使用习惯,功能闭环完整,用户路径清晰,客服咨询也会减少,下载、预览、转发一条龙,用户体验顺畅,功能完整度不输原生应用,运营反馈也正面。

App 端:WebView 集成

App 端 uni-app 通常渲染为 WebView,可以在 WebView 页面里加载 H5 页面,由 H5 页面完成 PDF 生成,导出能力一次实现、多端复用,App 端不用重复开发,维护成本显著降低,功能一致性也有保障,这是最省力的路径,H5 页面的全部能力在 App 内完整保留,用户无感知,开发团队也只需要维护一套导出代码,人力成本显著节省。

也可以把导出能力封装成一个独立的 H5 页面,App 内用 web-view 打开并传参,生成结果通过 web-view 的消息通道回传给 App,实现统一的导出交互,用户感知不到平台差异,体验流畅自然,代码结构也清晰好维护,WebView 与 H5 之间通过消息通道传参回传,整个链路闭环,调试也方便,用户无感知。

如果 App 使用原生渲染(nvue),导出 PDF 建议由后端生成或跳转 H5 页面处理;优先保证功能一致性,同时降低原生侧维护成本,避免在受限环境里硬啃能力边界,把精力放在核心业务上,技术选型更务实。

常见问题

Q: 集成后包体积会增加多少?A: dompdf.js 包含 WASM,建议按需加载(动态 import)并在构建时拆分 chunk,避免影响首屏加载速度,H5 端体验基本无感知,这是跨端项目的标准优化手段,按这个思路做不会踩坑,实测 H5 首屏加载几乎无感知,业务方可以放心接入,不用担心性能拖后腿,上线后也不会有投诉。

Q: 小程序里中文会乱码吗?A: 不会,内置思源黑体,HTML 字符串方案同样输出规范中文,与 H5 端效果一致,姓名、标题、正文都不会出现乱码,内容质量有保障,正式文档可以放心导出,小程序端的用户也能拿到和网页端一样清晰的 PDF,体验完全不降级,业务方也不用在小程序端做二次开发,交付效率更高。

Q: 三端代码要各写一套吗?A: 不需要,导出核心逻辑可以抽成公共模块,只有运行环境相关的部分用条件编译区分,大部分代码可以三端复用,维护成本可控,团队协作也更有条理,迭代效率明显更高,公共模块越沉淀越厚,后续新端接入速度更快,团队技术资产持续增值。

⚡ 现场演示(点击生成 PDF)

下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:

Hello from dompdf.js!

这是由 dompdf.js 渲染的示例 PDF 内容。