React でのセル結合と結合解除の実装ガイド
Web アプリケーション開発において、Excel ファイルのセル結合と結合解除は、データ表示やレポート生成の場面で頻繁に遭遇する要件です。セル結合は複数の隣接セルを1つの大きなセルに統合し、表ヘッダーの作成や分類データの視覚的グルーピングに役立ちます。結合解除はその逆で、結合された領域を元の個別セルに戻し、より細かいデータ編集を可能にします。本稿では、React フレームワークにおいて Spire.XLS for JavaScript の WebAssembly モジュールを利用して、これらの操作を実装する方法を紹介します。
環境設定と依存関係のインストール
React プロジェクトでは、まず npm を使用して必要なパッケージをインストールします:
npm install spire.office
インストール完了後、spire.xls.js と spire.xls.wasm の2つのファイルをプロジェクトの public ディレクトリに配置します。このライブラリは WebAssembly 技術を採用しており、ブラウザ環境では仮想ファイルシステム(Virtual File System, VFS)を介して Excel ファイルの読み取り、編集、保存を実行します。サーバーサイドの処理は不要です。
React コンポーネントで WASM モジュールを動的にロードする方法は以下の通りです:
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('WASM モジュールのロードに失敗しました:', error);
}
})();
}, []);
// ビジネスロジックは wasmModule の状態に依存
}
指定範囲のセルを結合する
CellRange.Merge() メソッドを使用すると、ワークシート内の指定された隣接セルを1つに結合できます。実装フローは以下の通りです:フォントと Excel ファイルを VFS にロードし、ワークブックインスタンスを作成し、対象のワークシートとセル範囲を特定し、結合操作を実行して結果を出力します。
const MergeCells = async () => {
const wasmModule = window.wasmModule?.spirexls;
if (!wasmModule) return;
// フォントファイルを仮想ファイルシステムにロード
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();
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 });
// VFS からファイルを読み取り、ブラウザダウンロードを実行
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() メソッドを使用します。このメソッドはセル参照を引数として受け取り、そのセルが属する結合領域全体に対して結合解除を実行します:
const UnmergeCells = async () => {
const wasmModule = window.wasmModule?.spirexls;
if (!wasmModule) return;
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();
// 保存とダウンロードのロジックは上記と同様
};
すべての結合セルを一括解除する
複数の結合領域を含む複雑な表の場合、個別に対処するのは現実的ではありません。Worksheet.MergedCells プロパティを使用すると、現在のワークシート内のすべての結合領域のリストを取得できます。これをループ処理し、各領域に対して UnMerge() を実行することで一括解除が実現できます:
const UnmergeAllCells = async () => {
const wasmModule = window.wasmModule?.spirexls;
if (!wasmModule) return;
// リソースロードの手順(上記と同様)
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 を動的にロードする際は、Webpack がパスを静的解析しないように /* webpackIgnore: true */ コメントを追加する必要があります。ロード成功後、モジュールインスタンスは window.wasmModule に格納され、spirexls サブオブジェクトが Excel 操作のコア API を提供します。
仮想ファイルシステムの利用制約:すべてのファイル操作はブラウザのメモリファイルシステム上で実行されます。テキストレンダリング用のフォントファイルと Excel ファイルは、事前に window.spire.FetchFileToVFS() で VFS にロードしておく必要があり、ロードパスは後続の LoadFromFile() および FS.readFile() の呼び出しと一致させる必要があります。
フォント依存と多言語サポート:Excel ドキュメントに日本語や中国語などの非 ASCII 文字が含まれる場合、VFS の /Library/Fonts/ ディレクトリに少なくとも1つの TrueType フォント(例:Arial.ttf)をロードする必要があります。フォントファイルが不足すると、出力ファイルで文字化けや文字欠落が発生する可能性があります。
リソース管理とメモリ解放:各操作完了後は、workbook.Dispose() を呼び出して .NET オブジェクトが占有するリソースを解放してください。複数のファイルを頻繁に処理するシナリオでは、リソース解放のタイミングがページパフォーマンスに直接影響します。
まとめ
ブラウザサイドでの Excel ファイル処理は近年成熟しつつあり、WebAssembly の導入によって従来バックエンドコンポーネントに依存していた負荷の高い操作がクライアントサイドで実行可能になりました。アーキテクチャの観点では、このアプローチはサーバーの計算負荷とネットワーク転送コストを効果的に削減しますが、その一方でリソース管理、ファイル I/O、例外処理の複雑さをフロントエンドに移すことになります。本稿で紹介した結合・結合解除機能は、VFS メカニズムを活用してブラウザメモリ上でファイルのロード、編集、エクスポートを行う一連の流れを示しました。実運用プロジェクトでは、WASM 初期化、ファイルロード、ダウンロードエクスポートといった共通処理を独立したモジュールとしてカプセル化し、ビジネスレイヤーのコードがセル範囲の論理記述に集中できるようにすることを推奨します。また、WebAssembly モジュールのロードはネットワーク環境とクロスオリジンポリシーの影響を受けるため、デプロイ時には spire.xls.js、spire.xls.wasm、および静的リソースファイルが正しいアクセスパスに配置されていることを確認し、コンポーネントレベルで適切なローディング状態の表示を設計して、ユーザーの待機体験を向上させることをお勧めします。