在使用 html2pdf.js 导出含中文的 HTML 内容时,常出现方块、问号或空白等乱码问题。根本原因在于其底层依赖的 jsPDF 默认仅支持 ASCII 字符集,未内置中文字体(如 SimSun、Noto Sans CJK),且未正确配置字体嵌入与编码映射。常见误区包括:仅修改 CSS `font-family` 而未注册字体;使用本地系统字体路径(浏览器无法访问);或未调用 `jsPDF.addFont()` 与 `html2pdf().set({ font: {...} })` 显式指定字体对象。此外,若 HTML 中 `<meta />` 缺失或字体文件(.ttf)未 Base64 编码加载,也会导致解析失败。解决方案需三步闭环:① 加载合规的开源中文字体(推荐 NotoSansCJKsc-Regular.ttf)并转为 Base64;② 通过 `jsPDF.addFont()` 注册并 `setFont()` 设为默认;③ 在 html2pdf 配置中启用 `useCORS: true`(跨域字体加载)及 `html2canvas: { useCORS: true }`。忽略任一环节均可能引发乱码。
1条回答 默认 最新
冯宣 2026-02-27 15:46关注```html一、现象层:乱码的典型表现与前端可观察线索
- 中文文本渲染为方块()、问号(?)或完全空白区域;
- PDF导出后英文正常,中文全部缺失或错位;
- 控制台无报错,但
jsPDF.getFontList()返回空数组或仅含helvetica等基础字体; - CSS 中设置
font-family: "SimSun", "Noto Sans CJK SC"无效; - 使用
html2pdf().from(element).save()直接调用时乱码,而手动构造 jsPDF 实例并 addFont 后可正常显示。
二、机制层:jsPDF 与 html2pdf.js 的字体处理链路剖析
html2pdf.js 是封装层,其核心流程为:
flowchart LR A[HTML DOM] --> B[html2canvas] B -->|Canvas bitmap| C[jsPDF.addImage] B -->|Text rendering| D[需字体支持] C --> E[PDF binary] D --> F[jsPDF.addFont + setFont] F --> G[Unicode 编码映射表] G --> H[TrueType 字体嵌入]HTML → html2canvas(截图)→ jsPDF(生成PDF)。关键断点如下:三、根源层:三大不可绕过的技术约束
约束维度 具体表现 违反后果 字符集支持 jsPDF 默认仅支持 ASCII + Latin-1 子集,无 UTF-8 / GBK 解析器 中文 Unicode 码点(U+4E00–U+9FFF)被截断或映射为 .notdef 字体嵌入机制 必须显式调用 addFont()并传入 Base64 字体数据,不能依赖 CSS font-family 或系统路径即使 CSS 指定 Noto Sans CJK,浏览器渲染正常,但 PDF 导出时字体未嵌入 → 降级为 Helvetica → 乱码 跨域资源加载 字体文件若托管在 CDN 或非同源服务,需启用 CORS;否则 fetch()失败,Base64 转换中断字体 ArrayBuffer 为空 → addFont()静默失败 →setFont()报错或无效果四、实践层:闭环式三步解决方案(含生产级代码)
- 字体准备与 Base64 封装:
下载 NotoSansCJKsc-Regular.ttf,使用工具(如 base64encode.org)转为 Base64 字符串,或通过 JS 动态加载:const fontData = 'AAEAAA...'; // 300KB+ Base64 字符串 - jsPDF 字体注册与设为默认:
const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.addFont(fontData, 'NotoSansCJKsc', 'normal'); doc.setFont('NotoSansCJKsc'); - html2pdf 全链路配置对齐:
html2pdf() .set({ margin: 10, filename: 'report.pdf', pagebreak: { mode: ['css', 'legacy'] }, useCORS: true, // ✅ 启用跨域字体/图片加载 html2canvas: { useCORS: true, // ✅ 必须双重启用 scale: 2, letterRendering: true }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } }) .from(element) .set({ font: { family: 'NotoSansCJKsc', size: 12 } }) // ✅ 显式注入字体对象 .save();
五、验证层:诊断清单与避坑指南
- ✅ 检查 HTML 是否声明
<meta charset="UTF-8">; - ✅ 确认字体 Base64 字符串开头为
data:font/truetype;base64,; - ✅ 在
html2pdf().set({...})后添加.then(() => console.log(jsPDF.getFontList()))验证注册成功; - ❌ 禁止使用
font-family: 'SimSun'—— 浏览器可访问,jsPDF 不可访问系统字体; - ❌ 禁止在
html2canvas配置中遗漏useCORS: true,尤其当字体来自 CDN 时; - ⚠️ 若使用 Webpack/Vite,需将 .ttf 文件
import并用URL.createObjectURL转换,避免打包污染。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报