在 React 应用中处理 Excel 文件时,单元格的合并与取消合并是一项常见需求。合并单元格可以将多个相邻单元格合并为一个跨列或跨行的大单元格,常用于创建表头或突出显示分组数据;取消合并则是将已合并的单元格恢复为独立的多个单元格,便于进行更细粒度的数据操作。本文将介绍如何在 React 中基于 Spire.XLS for JavaScript 的 WASM 模块实现这两种操作。
环境配置与安装
首先,在 React 项目中通过 npm 安装依赖:
bash
npm install spire.office
安装完成后,需要将 spire.xls.js 和 spire.xls.wasm 文件放置在项目的 public 目录下。该库基于 WebAssembly 运行,在浏览器端通过虚拟文件系统(VFS)管理 Excel 文件的读写,无需后端服务器支持。
在 React 组件中动态加载 WASM 模块的方式如下:
javascript
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;
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('加载 spire.xls.js WASM 模块失败:', error);
}
})();
}, []);
// 后续操作依赖 wasmModule 状态
}
合并 Excel 中的特定单元格
使用 CellRange.Merge() 方法可以将指定的相邻单元格合并为一个单元格。基本步骤如下:
- 将字体文件和目标 Excel 文件加载到虚拟文件系统(VFS)
- 创建
Workbook实例并加载 Excel 文件 - 获取目标工作表
- 指定需要合并的单元格范围并调用
Merge()方法 - 保存并导出文件
以下是一个完整的合并示例:
javascript
const MergeCells = async () => {
const wasmModule = window.wasmModule?.spirexls;
if (!wasmModule) return;
// 将字体加载到虚拟文件系统(VFS)中
await window.spire.FetchFileToVFS('Arial.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
// 将 Excel 文件加载到虚拟文件系统
const inputFileName = '合并单元格_input.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// 创建一个新的工作簿
const workbook = new wasmModule.Workbook();
// 从虚拟文件系统加载 Excel 文件
workbook.LoadFromFile(inputFileName);
// 获取第一个工作表
const sheet = workbook.Worksheets.get(0);
// 合并 A1 到 D1 区域的单元格
sheet.Range.get("A1:D1").Merge();
// 定义输出文件名并保存
const outputFileName = "合并单元格_output.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: wasmModule.ExcelVersion.Version2010 });
// 读取保存的文件并转换为 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);
// 清理资源
workbook.Dispose();
};
取消合并特定的单元格
取消合并的操作与合并类似,使用 CellRange.UnMerge() 方法即可。该方法适用于已知某个单元格属于合并区域的情况:
javascript
const UnmergeCells = async () => {
const wasmModule = window.wasmModule?.spirexls;
if (!wasmModule) return;
// 加载字体和 Excel 文件到 VFS
await window.spire.FetchFileToVFS('Arial.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
const inputFileName = '合并单元格.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);
// 取消合并 A1 单元格所在的合并区域
sheet.Range.get("A1").UnMerge();
// 保存并导出...
// 后续保存逻辑与合并示例相同
};
取消合并工作表中的所有合并单元格
当 Excel 文件中存在多个合并区域时,逐个处理较为繁琐。可以通过 Worksheet.MergedCells 属性获取工作表中的所有合并单元格列表,然后遍历执行取消合并操作:
javascript
const UnmergeAllCells = async () => {
const wasmModule = window.wasmModule?.spirexls;
if (!wasmModule) return;
// 加载字体和 Excel 文件到 VFS
await window.spire.FetchFileToVFS('Arial.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
const inputFileName = '合并单元格.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);
// 获取工作表中的所有合并区域
const range = sheet.MergedCells;
// 遍历并取消合并所有合并单元格
for (let cell of range) {
cell.UnMerge();
}
// 保存并导出...
// 后续保存逻辑与合并示例相同
};
操作注意事项
-
WASM 模块加载 :通过
import()动态加载spire.xls.js时需添加/* webpackIgnore: true */注释,防止 Webpack 打包时对路径进行解析。模块加载完成后会挂载到window.wasmModule对象上。 -
虚拟文件系统 :所有文件操作均在浏览器的虚拟文件系统中完成。字体文件和 Excel 文件需要通过
window.spire.FetchFileToVFS()预先加载,文件路径需与后续读取时保持一致。 -
字体依赖 :对于包含非英文文本(如中文、日文等)的 Excel 文件,需要将相应的 TrueType 字体文件(如
Arial.ttf)加载到 VFS 的/Library/Fonts/目录下,以确保文本渲染正确。 -
资源释放 :每次操作完成后应调用
workbook.Dispose()释放内存资源,避免在频繁操作时出现性能问题。 -
输出文件读取 :通过
window.dotnetRuntime.Module.FS.readFile()读取 VFS 中的输出文件,读取结果需转换为 Blob 对象并创建下载链接。
总结
从工程实践的角度来看,在前端处理 Excel 单元格合并操作的关键挑战并非 API 的调用本身,而在于浏览器环境下的资源管理和异步流程控制。WASM 模块的动态加载要求开发者妥善处理加载状态与用户交互的时序关系,虚拟文件系统的读写则依赖对 FetchFileToVFS 和 FS.readFile 的准确调用。字体预加载这一环节在实际开发中容易被忽略,但却是保证多语言内容正确输出的必要前提。本文提供的三种操作模式------指定区域合并、单点取消合并和全表批量取消------基本覆盖了日常开发中的主要需求。在实际项目中,建议将 WASM 加载、文件读写和下载触发等通用逻辑抽离为独立工具函数或自定义 Hook,降低业务组件与底层实现之间的耦合度。同时,由于 WebAssembly 在浏览器中的运行受同源策略和跨域资源共享(CORS)限制,部署时需确保 spire.xls.js、spire.xls.wasm 以及字体和数据文件均位于正确的可访问路径下,以避免因资源加载失败导致的运行时错误。