在日常的 Word 文档开发中,合并与拆分表格单元格是最常见的表格编辑操作之一。无论是制作带有跨列标题的报表表头,还是实现跨行合并的产品分组展示,单元格合并都能让表格结构更加清晰合理。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成 Word 文档的创建与编辑,通过虚拟文件系统(VFS)管理字体和文件资源,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
合并与拆分单元格
在实际开发中,最常遇到的需求是对已有表格进行结构调整:将多个相邻的单元格合并为一个,或者将一个单元格拆分为多行多列。Spire.Doc 提供了 ApplyHorizontalMerge、ApplyVerticalMerge 和 SplitCell 三个方法分别实现水平合并、垂直合并和拆分操作。核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和目标 Word 文件载入 WASM 虚拟文件系统;然后实例化 Document 加载文件,获取目标表格后调用合并与拆分方法;最后将文档保存并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
function App() {
const MergeAndSplitTableCell = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例 Word 文件载入 VFS
let inputFileName = "TableSample.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 水平合并:将第 6 行的第 2、3 列合并
table.ApplyHorizontalMerge(6, 2, 3);
// 垂直合并:将第 2 列的第 4、5 行合并
table.ApplyVerticalMerge(2, 4, 5);
// 拆分单元格:将第 8 行第 3 列的单元格拆分为 2 行 2 列
table.Rows.get_Item(8).Cells.get_Item(3).SplitCell(2, 2);
// 定义输出文件名
const outputFileName = "MergeAndSplitTableCell_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Dispose();
// 从 VFS 读取生成的文件,触发下载
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>单击以下按钮以在Word文档中合并和拆分表格单元格。</h1>
<button onClick={MergeAndSplitTableCell}>
Generate
</button>
</div>
);
}
export default App;
生成的 Word 文档效果如下:

合并单元格后格式化
合并单元格后,通常还需要对合并后的区域进行格式化,例如设置字体样式、对齐方式和背景色,以提升表格的可读性和美观度。下面的示例演示了如何创建一个产品价格表,合并表头"Product"单元格和左侧的版本类别单元格,并对其应用自定义样式。
function AddTable(section) {
let wasmModule = window.wasmModule.spiredoc;
let table = section.AddTable({ showBorder: true });
table.ResetCells(4, 3);
// 表格数据
let dt = [["产品", "", "库存(kg)"],
["水果", "苹果", "150"],
["", "葡萄", "200"],
["", "柠檬", "100"]];
for (let r = 0; r < dt.length; r++) {
let dataRow = table.Rows.get_Item(r);
dataRow.Height = 20;
dataRow.HeightType = wasmModule.TableRowHeightType.Exactly;
for (let i = 0; i < dataRow.Cells.Count; i++) {
dataRow.Cells.get_Item(i).CellFormat.Shading.BackgroundPatternColor = wasmModule.Color.Empty;
}
for (let c = 0; c < dataRow.Cells.Count; c++) {
if (dt[r][c] !== "") {
let range = dataRow.Cells.get_Item(c).AddParagraph().AppendText(dt[r][c]);
range.CharacterFormat.FontName = "Arial";
}
}
}
return table;
}
function App() {
const FormatMergedCells = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体和文档文件载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建 Word 文档
let doc = new wasmModule.Document();
let section = doc.AddSection();
// 添加表格
let table = AddTable(section);
// 创建自定义样式
let style = new wasmModule.ParagraphStyle(doc);
style.Name = "Style";
style.CharacterFormat.TextColor = wasmModule.Color.get_DeepSkyBlue();
style.CharacterFormat.Italic = true;
style.CharacterFormat.Bold = true;
style.CharacterFormat.FontSize = 13;
doc.Styles.Add(style);
// 水平合并:将第一行的第 0、1 列合并
table.ApplyHorizontalMerge(0, 0, 1);
// 应用样式
table.Rows.get_Item(0).Cells.get_Item(0).Paragraphs.get_Item(0).ApplyStyle(style.Name);
// 设置垂直和水平对齐
table.Rows.get_Item(0).Cells.get_Item(0).CellFormat.VerticalAlignment = wasmModule.VerticalAlignment.Middle;
table.Rows.get_Item(0).Cells.get_Item(0).Paragraphs.get_Item(0).Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
// 垂直合并:将第 0 列的第 1、2、3 行合并
table.ApplyVerticalMerge(0, 1, 3);
// 应用样式
table.Rows.get_Item(1).Cells.get_Item(0).Paragraphs.get_Item(0).ApplyStyle(style.Name);
// 设置垂直和水平对齐
table.Rows.get_Item(1).Cells.get_Item(0).CellFormat.VerticalAlignment = wasmModule.VerticalAlignment.Middle;
table.Rows.get_Item(1).Cells.get_Item(0).Paragraphs.get_Item(0).Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Left;
// 设置列宽占比
table.Rows.get_Item(1).Cells.get_Item(0).SetCellWidth(20, wasmModule.CellWidthType.Percentage);
// 定义输出文件名
const outputFileName = "FormatMergedCells_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Dispose();
// 从 VFS 读取生成的文件,触发下载
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>单击以下按钮以格式化合并的单元格。</h1>
<button onClick={FormatMergedCells}>
Generate
</button>
</div>
);
}
export default App;
生成的 Word 文档效果如下:

检测单元格合并状态
在处理他人创建的文档或自动化流程生成的表格时,常常需要先了解哪些单元格已被合并,以避免操作索引越界。Spire.Doc 通过 CellFormat.VerticalMerge 和 Cell.GridSpan 两个属性来检测单元格的合并状态:VerticalMerge 指示垂直合并情况,GridSpan 表示水平合并跨越的列数。
function App() {
const CellMergeStatus = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文件载入 VFS
let inputFileName = "CellMergeStatus.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节和第一个表格
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 遍历所有单元格,检测合并状态
let stringBuidler = [];
for (let i = 0; i < table.Rows.Count; i++) {
let tableRow = table.Rows.get_Item(i);
for (let j = 0; j < tableRow.Cells.Count; j++) {
let tableCell = tableRow.Cells.get_Item(j);
let verticalMerge = tableCell.CellFormat.VerticalMerge;
let horizontalMerge = tableCell.GridSpan;
if (verticalMerge === wasmModule.CellMerge.None && horizontalMerge === 1) {
stringBuidler.push("Row " + i + ", cell " + j + ": ");
stringBuidler.push("This cell isn't merged.\n");
} else {
stringBuidler.push("Row " + i + ", cell " + j + ": ");
stringBuidler.push("This cell is merged.\n");
}
}
stringBuidler.push("\n");
}
// 定义输出文件名
const outputFileName = "CellMergeStatus_output.txt";
// 将检测结果写入文本文件
window.dotnetRuntime.Module.FS.writeFile(outputFileName, stringBuidler.join('\n'));
// 从 VFS 读取生成的文件,触发下载
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>单击以下按钮以获取 Word 文档中单元格的合并状态。</h1>
<button onClick={CellMergeStatus}>
Generate
</button>
</div>
);
}
export default App;
检测结果以文本文件输出:

常见问题
合并后的单元格如何判断是否合并成功
原因:合并操作本身不返回状态值,需要通过读取单元格属性来确认。
解决:使用 CellFormat.VerticalMerge 判断垂直合并类型(CellMerge.None 表示未合并),使用 Cell.GridSpan 判断水平合并跨越的列数(值为 1 表示未合并):
let verticalMerge = tableCell.CellFormat.VerticalMerge;
let horizontalMerge = tableCell.GridSpan;
if (verticalMerge === wasmModule.CellMerge.None && horizontalMerge === 1) {
// 未合并
} else {
// 已合并
}
拆分单元格后内容丢失
原因:SplitCell 方法将单元格拆分为多个子单元格后,原有内容默认保留在第一个子单元格中。
解决:拆分后手动遍历子单元格重新分配内容,或拆分前通过 Paragraphs 集合备份单元格文本:
// 备份内容
let cell = table.Rows.get_Item(row).Cells.get_Item(col);
let text = cell.Paragraphs.get_Item(0).Text;
// 拆分为 2 行 2 列
cell.SplitCell(2, 2);
// 将内容写入新的单元格
table.Rows.get_Item(row).Cells.get_Item(col).Paragraphs.get_Item(0).AppendText(text);
合并单元格时索引超出范围
原因:ApplyHorizontalMerge(row, startCol, endCol) 和 ApplyVerticalMerge(col, startRow, endRow) 的索引从 0 开始,传入的索引超出表格的实际行列数会引发错误。
解决:合并前检查表格的行列数,确保结束索引不超过 Rows.Count - 1 和 Cells.Count - 1:
if (endCol < table.Rows.get_Item(row).Cells.Count && endRow < table.Rows.Count) {
table.ApplyHorizontalMerge(row, startCol, endCol);
}
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。









