使用JavaScript在React中实现Word转PDF功能

 更新时间:2026年07月06日 08:38:47   作者:Eiceblue  
在 React 项目中实现 Word 转 PDF,是文档管理系统、电子合同签署、报告生成等场景的常见需求,本文将基于 Spire.Doc for JavaScript 库,系统性地介绍如何在 React 中实现这一功能,需要的朋友可以参考下

在 React 项目中实现 Word 转 PDF,是文档管理系统、电子合同签署、报告生成等场景的常见需求。相比于依赖后端服务,在浏览器端(客户端)直接完成转换具有显著优势:文件无需上传至服务器,既降低了带宽消耗和服务器负载,又避免了文档内容在传输过程中泄露的风险,对数据隐私要求较高的业务尤其友好。

本文将基于 Spire.Doc for JavaScript 库,系统性地介绍如何在 React 中实现这一功能。我们会从环境搭建讲起,逐步深入到字体嵌入、权限加密、书签保留等进阶配置,并提供完整的可运行示例。

一、技术原理简述:WebAssembly 与虚拟文件系统

在开始编码前,有必要简单了解其底层机制。Spire.Doc for JavaScript 的核心是一个 WASM(WebAssembly) 模块。它将 C++ 编写的文档解析引擎编译为浏览器可执行的二进制格式,因此能够在浏览器中高效地处理 Word 文档。

值得注意的是,WASM 运行在一个独立的沙箱环境中,它无法直接读写您电脑硬盘上的文件。为此,该库实现了一个 虚拟文件系统(VFS,Virtual File System)。在代码中看到的 FetchFileToVFSFS.readFile 等操作,都是围绕这个虚拟文件系统进行的:

  1. 写入 VFS:通过 FetchFileToVFSpublic 目录下的静态资源(字体文件、模板文档)加载到 WASM 内存中。
  2. 处理文档Document 对象从 VFS 中读取源文件,执行转换操作,并将结果输出到 VFS。
  3. 读取 VFS:转换完成后,通过 FS.readFile 从 VFS 中读取生成的 PDF 二进制数据,再通过浏览器 API 触发下载。

理解这一流程后,后续的代码阅读就会豁然开朗。

二、项目初始化与环境配置

1. 安装 Node.js 与创建 React 项目

首先,从 Node.js 官网 下载并安装 Node.js。安装完成后,在终端中运行以下命令验证安装是否成功:

node -v
npm -v

然后创建一个新的 React 项目(以 Create React App 为例):

npx create-react-app my-app
cd my-app

2. 安装依赖包

Spire.Office for JavaScript 整合了 Spire.DocSpire.XLSSpire.PDFSpire.Presentation 四个核心组件。在项目根目录执行以下命令安装:

npm i spire.office

3. 迁移核心运行时文件

安装完成后,需要将 lib 中的以下五个文件及文件夹复制到 React 项目的 public 文件夹中:

  • spire.doc.js
  • Spire.Doc.Wasm.zip
  • spire.common.js
  • Spire.Common.Wasm.zip
  • _framework 文件夹

为什么放在 public?因为 WASM 加载需要通过 JavaScript 主线程以异步方式请求 .wasm 文件及相关资源。放在 public 目录下可以确保构建工具(如 Webpack)不会错误地处理或重命名它们,且能通过 process.env.PUBLIC_URL 准确访问。

4. 准备字体资源(关键步骤)

浏览器和 WASM 环境默认不包含系统字体。如果待转换的 Word 文档中使用了特殊字体(如 Calibri、Times New Roman 或中文字体),而 VFS 中缺失该字体,转换出的 PDF 可能会出现乱码或文本错位。

建议将项目常用字体(如 CALIBRI.ttfMSYH.TTC 等)一并放入 public 目录。后续代码会通过 FetchFileToVFS 将这些字体预加载到 VFS 中。

三、基础转换:Word 转 PDF

以下是一个完整的转换示例,实现了从加载字体和 Word 文件,到生成 PDF 并触发浏览器下载的完整流程。

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,实现“所见即所得”。

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)。
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 左侧生成导航目录树,极大提升长文档的浏览效率。

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,我们不仅绕开了后端文件处理的瓶颈,还利用虚拟文件系统和精细的参数配置,实现了字体嵌入、文档加密、书签保留等企业级特性。

以上就是使用JavaScript在React中实现Word转PDF功能的详细内容,更多关于JavaScript React实现Word转PDF的资料请关注脚本之家其它相关文章!

相关文章

  • ie下js不执行的几种可能

    ie下js不执行的几种可能

    本文主要介绍了ie下js不执行的几种可能,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • JavaScript解决Joseph问题

    JavaScript解决Joseph问题

    JavaScript解决Joseph问题...
    2007-02-02
  • 使用PBFunc在Powerbuilder中支付宝当面付款功能

    使用PBFunc在Powerbuilder中支付宝当面付款功能

    这篇文章主要介绍了使用PBFunc在Powerbuilder中支付宝当面付款功能的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-10-10
  • JavaScript之AOP编程实例

    JavaScript之AOP编程实例

    这篇文章主要介绍了JavaScript的AOP编程,以实例形式分析了javascript面向切面编程的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • 简单方法判断JavaScript对象为null或者属性为空

    简单方法判断JavaScript对象为null或者属性为空

    对已声明但未初始化的和未声明的变量执行typeof,都返回undefined,null表示一个空对象指针,typeof操作会返回object
    2014-09-09
  • js实现页面跳转重定向的几种方式

    js实现页面跳转重定向的几种方式

    这篇文章主要介绍js实现页面跳转重定向的几种方式,需要的朋友可以参考下
    2014-05-05
  • TS中最常见的声明合并(接口合并)

    TS中最常见的声明合并(接口合并)

    这篇文章主要介绍了TS中最常见的声明合并:接口合并,TS中的声明合并,指的就是编译器会针对同名的声明合并为一个声明,合并后的声明会同时拥有原先两个或多个声明的特性,接口的合并也是一样,它会将双方的成员放到一个同名的接口里,更多详细内容请参考下面文章内容

    2021-12-12
  • three.js绘制地球、飞机与轨迹的效果示例

    three.js绘制地球、飞机与轨迹的效果示例

    Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。下面这篇文章主要给大家介绍了利用three.js如何绘制地球、飞机与轨迹的效果,文中给出了详细的示例代码,需要的朋友们可以参考借鉴,下面来一起看看吧。
    2017-02-02
  • 8 行 Node.js 代码实现代理服务器

    8 行 Node.js 代码实现代理服务器

    JavaScript 前后端通吃,在全栈开发领域具有独特的优势。今天就来看看作为服务端语言的 JavaScript,完成一个简单的代理服务器功能是多么容易。
    2016-12-12
  • JS实现颜色的10进制转化成rgba格式的方法

    JS实现颜色的10进制转化成rgba格式的方法

    这篇文章主要介绍了JS实现颜色的10进制转化成rgba格式的方法,涉及javascript针对颜色数值转换的相关运算操作技巧,需要的朋友可以参考下
    2017-09-09

最新评论