在 React 项目中实现 Word 转 PDF,是文档管理系统、电子合同签署、报告生成等场景的常见需求。相比于依赖后端服务,在浏览器端(客户端)直接完成转换具有显著优势:文件无需上传至服务器,既降低了带宽消耗和服务器负载,又避免了文档内容在传输过程中泄露的风险,对数据隐私要求较高的业务尤其友好。
本文将基于 Spire.Doc for JavaScript 库,系统性地介绍如何在 React 中实现这一功能。我们会从环境搭建讲起,逐步深入到字体嵌入、权限加密、书签保留等进阶配置,并提供完整的可运行示例。
文章目录
-
- [一、技术原理简述:WebAssembly 与虚拟文件系统](#一、技术原理简述:WebAssembly 与虚拟文件系统)
- 二、项目初始化与环境配置
-
- [1. 安装 Node.js 与创建 React 项目](#1. 安装 Node.js 与创建 React 项目)
- [2. 安装依赖包](#2. 安装依赖包)
- [3. 迁移核心运行时文件](#3. 迁移核心运行时文件)
- [4. 准备字体资源(关键步骤)](#4. 准备字体资源(关键步骤))
- [三、基础转换:Word 转 PDF](#三、基础转换:Word 转 PDF)
- 四、进阶转换参数详解(`ToPdfParameterList`)
-
- [1. 彻底解决字体问题:嵌入所有字体](#1. 彻底解决字体问题:嵌入所有字体)
- [2. 保护敏感内容:PDF 加密与权限控制](#2. 保护敏感内容:PDF 加密与权限控制)
- [3. 优化长篇文档体验:保留书签(大纲导航)](#3. 优化长篇文档体验:保留书签(大纲导航))
- 五、总结
一、技术原理简述:WebAssembly 与虚拟文件系统
在开始编码前,有必要简单了解其底层机制。Spire.Doc for JavaScript 的核心是一个 WASM(WebAssembly) 模块。它将 C++ 编写的文档解析引擎编译为浏览器可执行的二进制格式,因此能够在浏览器中高效地处理 Word 文档。
值得注意的是,WASM 运行在一个独立的沙箱环境中,它无法直接读写您电脑硬盘上的文件。为此,该库实现了一个 虚拟文件系统(VFS,Virtual File System) 。在代码中看到的 FetchFileToVFS、FS.readFile 等操作,都是围绕这个虚拟文件系统进行的:
- 写入 VFS :通过
FetchFileToVFS将public目录下的静态资源(字体文件、模板文档)加载到 WASM 内存中。 - 处理文档 :
Document对象从 VFS 中读取源文件,执行转换操作,并将结果输出到 VFS。 - 读取 VFS :转换完成后,通过
FS.readFile从 VFS 中读取生成的 PDF 二进制数据,再通过浏览器 API 触发下载。
理解这一流程后,后续的代码阅读就会豁然开朗。
二、项目初始化与环境配置
1. 安装 Node.js 与创建 React 项目
首先,从 Node.js 官网 下载并安装 Node.js。安装完成后,在终端中运行以下命令验证安装是否成功:
bash
node -v
npm -v
然后创建一个新的 React 项目(以 Create React App 为例):
bash
npx create-react-app my-app
cd my-app
2. 安装依赖包
Spire.Office for JavaScript 整合了 Spire.Doc、Spire.XLS、Spire.PDF 和 Spire.Presentation 四个核心组件。在项目根目录执行以下命令安装:
bash
npm i spire.office
3. 迁移核心运行时文件
安装完成后,需要将 lib 中的以下五个文件及文件夹复制到 React 项目的 public 文件夹中:
spire.doc.jsSpire.Doc.Wasm.zipspire.common.jsSpire.Common.Wasm.zip_framework文件夹
为什么放在
public?因为 WASM 加载需要通过 JavaScript 主线程以异步方式请求.wasm文件及相关资源。放在public目录下可以确保构建工具(如 Webpack)不会错误地处理或重命名它们,且能通过process.env.PUBLIC_URL准确访问。
4. 准备字体资源(关键步骤)
浏览器和 WASM 环境默认不包含系统字体。如果待转换的 Word 文档中使用了特殊字体(如 Calibri、Times New Roman 或中文字体),而 VFS 中缺失该字体,转换出的 PDF 可能会出现乱码或文本错位。
建议将项目常用字体(如 CALIBRI.ttf、MSYH.TTC 等)一并放入 public 目录。后续代码会通过 FetchFileToVFS 将这些字体预加载到 VFS 中。

三、基础转换:Word 转 PDF
以下是一个完整的转换示例,实现了从加载字体和 Word 文件,到生成 PDF 并触发浏览器下载的完整流程。
javascript
import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
// 组件挂载时加载 WASM 模块
useEffect(() => {
const loadWasm = async () => {
try {
const publicUrl = process.env.PUBLIC_URL || '';
// 动态导入 spire.doc.js(从 public 目录加载)
const spireModule = await import(
/* webpackIgnore: true */ `${publicUrl}/spire.doc.js`
);
const rawModule = spireModule.default || spireModule;
// 初始化 WASM 模块,locateFile 用于指定 .wasm 文件位置
const module = await rawModule({
locateFile: (p) =>
p.endsWith('.wasm') ? `${publicUrl}/${p}` : p,
});
// 模块初始化完成后暴露在 window.spire 下
setWasmModule(window.spire);
} catch (error) {
console.error('Failed to load WASM module:', error);
}
};
loadWasm();
}, []);
const convertWordToPdf = async () => {
if (!wasmModule) {
alert('文档处理引擎尚未加载完成,请稍候');
return;
}
// 1. 加载字体到虚拟文件系统(VFS)
await window.spire.FetchFileToVFS(
'CALIBRI.ttf',
'/Library/Fonts/',
`${process.env.PUBLIC_URL}/`
);
// 2. 加载待转换的 Word 文件到 VFS
const inputFileName = 'Roche.docx';
await window.spire.FetchFileToVFS(
inputFileName,
'',
`${process.env.PUBLIC_URL}/`
);
// 3. 创建文档对象并加载 Word 文件
const doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 4. 转换为 PDF
const outputFileName = 'ToPDF.pdf';
doc.SaveToFile({
fileName: outputFileName,
fileFormat: wasmModule.FileFormat.PDF,
});
// 5. 从 VFS 读取生成的 PDF 并触发下载
const fileArray = wasmModule.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
// 6. 释放资源
doc.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Word 转 PDF 示例</h1>
<button onClick={convertWordToPdf} disabled={!wasmModule}>
转换
</button>
</div>
);
}
export default App;
代码要点说明:
- 加载方式 :使用
import()动态加载spire.doc.js,配合locateFile指定.wasm文件位置。/* webpackIgnore: true */注释用于防止 Webpack 处理该动态导入路径,确保从public目录加载。 - 模块引用 :初始化完成后,通过
window.spire访问 API。 - 文档创建 :使用
new wasmModule.Document()创建文档实例。 FetchFileToVFS:将字体和 Word 文件加载到虚拟文件系统中。FS.readFile:从 VFS 中读取生成的 PDF 文件。- 资源释放 :转换完成后调用
doc.Dispose()释放内存。
四、进阶转换参数详解(ToPdfParameterList)
基础转换仅能满足简单的需求。为了应对复杂的业务场景,Spire.Doc 提供了 ToPdfParameterList 参数类,允许我们对转换过程进行精细控制。
1. 彻底解决字体问题:嵌入所有字体
默认情况下,PDF 会引用系统字体。如果目标阅读设备缺少对应字体,显示会回退。将 IsEmbeddedAllFonts 设为 true 可以将文档中用到的所有字符轮廓嵌入 PDF,实现"所见即所得"。
javascript
const convertWithFonts = async () => {
if (!wasmModule) return;
// 加载字体和文件到 VFS
await window.spire.FetchFileToVFS('CALIBRI.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/`);
await window.spire.FetchFileToVFS('Roche.docx', '', `${process.env.PUBLIC_URL}/`);
const doc = new wasmModule.Document();
doc.LoadFromFile('Roche.docx');
// 创建转换参数对象
let parameters = new wasmModule.ToPdfParameterList();
// 嵌入所有字体
parameters.IsEmbeddedAllFonts = true;
// 针对某些特殊私有字体,还可以单独指定路径
const privateFont = wasmModule.PrivateFontPath.Create('MyCustomFont', 'custom.ttf');
parameters.PrivateFontPaths = [privateFont];
const outputFileName = 'ToPDF_with_Fonts.pdf';
doc.SaveToFile({ fileName: outputFileName, paramList: parameters });
// ... 读取并下载逻辑同上
doc.Dispose();
};
2. 保护敏感内容:PDF 加密与权限控制
对于合同、标书等保密文档,加密至关重要。PdfSecurity.Encrypt 方法接受四个核心参数:
- 打开密码:用户打开 PDF 时必须输入的密码。
- 权限密码:用于修改权限设置的管理员密码(与打开密码不同)。
- 权限标志:控制是否允许打印、复制内容、修改文档等。
- 加密强度 :一般选用 128 位密钥(
Key128Bit)。
javascript
const convertWithEncryption = async () => {
// ... 加载字体和文件 ...
let parameters = new wasmModule.ToPdfParameterList();
// 加密 PDF
parameters.PdfSecurity.Encrypt(
'user123', // 用户打开密码
'admin456', // 所有者权限密码
wasmModule.PdfPermissionsFlags.Print | wasmModule.PdfPermissionsFlags.Copy, // 仅允许打印和复制
wasmModule.PdfEncryptionKeySize.Key128Bit // 128 位加密强度
);
const outputFileName = 'ToPDF_Encrypted.pdf';
doc.SaveToFile({ fileName: outputFileName, paramList: parameters });
// ... 下载及资源释放
};
3. 优化长篇文档体验:保留书签(大纲导航)
如果 Word 文档中已经通过标题样式(Heading 1/2/3)添加了书签,设置 CreateWordBookmarks = true 可以在生成的 PDF 左侧生成导航目录树,极大提升长文档的浏览效率。
javascript
const convertWithBookmarks = async () => {
// ... 加载字体和文件 ...
let parameters = new wasmModule.ToPdfParameterList();
// 从 Word 标题创建 PDF 书签
parameters.CreateWordBookmarks = true;
const outputFileName = 'ToPDF_with_Bookmarks.pdf';
doc.SaveToFile({ fileName: outputFileName, paramList: parameters });
// ... 下载及资源释放
};
五、总结
本文详细介绍了在 React 生态中利用 WebAssembly 技术实现客户端 Word 转 PDF 的完整路径。通过 Spire.Office for JavaScript,我们不仅绕开了后端文件处理的瓶颈,还利用虚拟文件系统和精细的参数配置,实现了字体嵌入、文档加密、书签保留等企业级特性。
------使用中遇到问题,可以在论坛上交流讨论-----------