普通网友 2026-02-27 15:45 采纳率: 98.6%
浏览 2
已采纳

html2pdf.js导出PDF时中文乱码怎么解决?

在使用 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 是封装层,其核心流程为:HTML → html2canvas(截图)→ jsPDF(生成PDF)。关键断点如下:

    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 字体嵌入]

    三、根源层:三大不可绕过的技术约束

    约束维度具体表现违反后果
    字符集支持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() 报错或无效果

    四、实践层:闭环式三步解决方案(含生产级代码)

    1. 字体准备与 Base64 封装
      下载 NotoSansCJKsc-Regular.ttf,使用工具(如 base64encode.org)转为 Base64 字符串,或通过 JS 动态加载:
      const fontData = 'AAEAAA...'; // 300KB+ Base64 字符串
    2. jsPDF 字体注册与设为默认
      const { jsPDF } = window.jspdf;
      const doc = new jsPDF();
      doc.addFont(fontData, 'NotoSansCJKsc', 'normal');
      doc.setFont('NotoSansCJKsc');
    3. 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 转换,避免打包污染。
    ```
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 2月28日
  • 创建了问题 2月27日