React 前端实战:JavaScript 实现 Excel 工作簿的保护与取消保护

在 B 端业务开发中,前端经常需要处理 Excel 文件的生成与导出。除了基础的数据写入,某些场景下我们还需要对文件施加安全控制,比如对整个工作簿加密、限制工作表的编辑权限,或者解除已有的保护。本文将结合 Spire.XLS for JavaScript,详细介绍在 React 项目中如何通过 JavaScript 实现这些操作。

环境搭建

首先通过 npm 安装依赖包:

npm i spire.office

安装完成后,在 React 组件中引入 WASM 模块。由于该库基于 WebAssembly 实现,使用时需要先异步加载引擎。通常的做法是在 useEffect 中完成初始化,并将加载状态通过 useState 管理,以控制后续操作的可用性:

import React, { useState, useEffect } from 'react';

function App() {
  const [wasmModule, setWasmModule] = useState(null);

  useEffect(() => {
    (async () => {
      try {
        const publicUrl = process.env.PUBLIC_URL || '';
        const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.xls.js`);
        const rawModule = spireModule.default || spireModule;
        window.wasmModule = typeof rawModule === 'function'
          ? await rawModule({ locateFile: p => p.endsWith('.wasm') ? `${publicUrl}/${p}` : p })
          : rawModule;
        setWasmModule(window.wasmModule);
      } catch (error) {
        console.error('WASM 模块加载失败:', error);
      }
    })();
  }, []);

  // 后续操作方法将在此处定义...
}

这里使用动态 import 加载 spire.xls.js,并指定 WASM 文件的路径。加载成功后将模块实例存入 window.wasmModule,方便后续调用。wasmModule 状态则用于控制按钮的可点击状态,避免在引擎未就绪时触发操作。

操作前的准备工作

在实际处理 Excel 文件前,有两项资源需要预先加载到库的虚拟文件系统(VFS)中:字体文件和待处理的 Excel 文件。字体文件用于保证文档中的文字能正常渲染,Excel 文件则是我们要操作的数据源。

// 加载字体到 VFS
await window.spire.FetchFileToVFS('Arial.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);

// 加载 Excel 文件到 VFS
const inputFileName = 'sample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

FetchFileToVFS 的三个参数依次为:文件名、VFS 中的目标目录、浏览器端的源文件路径。以上代码假设字体文件存放在 public/static/font/ 目录下,Excel 文件存放在 public/static/data/ 目录下。开发者可根据项目实际结构调整路径。

使用密码保护整个工作簿

工作簿级别的保护会要求用户在打开文件时输入密码,适用于需要控制文件访问权限的场景。下面是一个完整的处理函数:

const EncryptExcel = async () => {
  const wasmModule = window.wasmModule.spirexls;

  if (wasmModule) {
    // 加载字体和源文件到 VFS(此处省略,实际开发需保留)
    // ...

    // 创建工作簿实例并加载文件
    const workbook = new wasmModule.Workbook();
    workbook.LoadFromFile(inputFileName);

    // 使用密码加密工作簿
    workbook.Protect('password');

    // 定义输出文件名并保存
    const outputFileName = '加密Excel文件.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: wasmModule.ExcelVersion.Version2010 });

    // 从 VFS 读取生成的文件,转换为 Blob 并触发下载
    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const modifiedFile = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });

    const url = URL.createObjectURL(modifiedFile);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);

    // 释放 WASM 资源
    workbook.Dispose();
  }
};

整体流程可概括为五步:加载文件到 VFS → 创建 Workbook 实例 → 调用 Protect 设置密码 → 保存文件 → 从 VFS 读取并下载。其中 SaveToFileversion 参数指定了输出文件的 Excel 版本格式,这里使用 Version2010.xlsx 格式。操作完成后调用 Dispose 是一个好习惯,可以及时释放 WebAssembly 占用的内存。

设置特定权限保护工作表

有时我们并不需要加密整个文件,而是希望限制用户对某个工作表的操作。比如分发数据报表时,允许查看但不允许修改。此时可以通过设置工作表保护类型来实现细粒度控制:

const EncryptExcelWorksheet = async () => {
  const wasmModule = window.wasmModule.spirexls;

  if (wasmModule) {
    // 加载字体和源文件到 VFS(此处省略)
    // ...

    const workbook = new wasmModule.Workbook();
    workbook.LoadFromFile(inputFileName);

    // 获取第一个工作表
    const sheet = workbook.Worksheets.get(0);

    // 使用特定权限保护工作表
    sheet.Protect({ password: '123456', options: wasmModule.SheetProtectionType.None });

    // 保存并下载(与上文下载逻辑相同,此处省略)
    // ...

    workbook.Dispose();
  }
};

这里的关键参数是 SheetProtectionType,示例中使用了 None 表示禁止所有用户操作。库还提供了其他保护类型,开发者可以根据需求组合使用,例如仅禁止格式化而允许数据选择等。这种精细化的权限设置在制作标准化数据采集模板时非常实用。

取消工作表的保护

当文件需要重新编辑时,可以通过正确的密码解除工作表保护:

const UnprotectExcelWorksheet = async () => {
  const wasmModule = window.wasmModule.spirexls;

  if (wasmModule) {
    // 加载受保护的 Excel 文件到 VFS
    const inputFileName = '加密Excel工作表.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

    const workbook = new wasmModule.Workbook();
    workbook.LoadFromFile(inputFileName);

    // 获取需要取消保护的工作表
    const sheet = workbook.Worksheets.get(0);

    // 使用正确密码移除保护
    sheet.Unprotect('password');

    // 保存并下载(此处省略)
    // ...

    workbook.Dispose();
  }
};

解除保护后保存的新文件将不再受工作表编辑限制。值得注意的是,如果密码输入错误,Unprotect 方法会抛出异常。在生产环境中,建议使用 try-catch 捕获异常并给用户相应的提示信息。

组件整合示例

将上述功能整合到一个 React 组件中,完整的渲染结构如下:

return (
  <div style={{ textAlign: 'center', height: '300px' }}>
    <h1>React 中 JavaScript 保护与取消保护 Excel 工作簿</h1>
    <button onClick={EncryptExcel} disabled={!wasmModule}>
      加密工作簿并下载
    </button>
    <button onClick={EncryptExcelWorksheet} disabled={!wasmModule}>
      保护工作表并下载
    </button>
    <button onClick={UnprotectExcelWorksheet} disabled={!wasmModule}>
      解除工作表保护并下载
    </button>
  </div>
);

通过 disabled={!wasmModule} 确保在 WASM 引擎加载完成前按钮不可点击,避免因过早调用导致运行时错误。

技术要点小结

回顾整个实现过程,有几个关键点值得注意:

第一,WASM 模块的初始化是异步过程,务必在加载完成后再进行文件操作,否则会因引擎未就绪而报错。

第二,库使用独立的虚拟文件系统管理文件,输入文件需要先通过 FetchFileToVFS 导入,输出文件则需要通过 FS.readFile 读取后再转换格式。这与直接操作浏览器文件系统的思路有所不同。

第三,密码在示例中以明文形式写在代码中。如果项目对安全性有较高要求,建议改为由用户在页面上输入密码,避免将敏感信息直接暴露在前端代码中。

第四,每次操作完成后调用 Dispose 有助于释放 WebAssembly 内存,尤其是在连续处理多个文件的场景下更应关注资源管理。

结语

通过上述示例可以看到,在 React 前端项目中实现对 Excel 工作簿和工作表的保护与取消保护是可行的。整个过程不依赖后端服务,所有文件处理均在浏览器端完成,这种方案在需要纯前端处理文档的场景中具有一定的实用价值。无论是生成受控的数据报表,还是为用户提供文件加密工具,本文介绍的技术思路都可以作为参考基础进行扩展。希望这些内容对正在探索前端文档处理方向的开发者有所帮助。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容