OFD(Open Fixed-layout Document)是国家标准的版式文档格式,广泛应用于电子发票、电子证照、行政审批等政务与金融场景。OFD 基于 XML 描述文档结构,具有自主可控、信息安全等优势。与此同时,PDF 作为国际通用的文档格式在跨平台分发领域依然不可或缺。实际业务中经常需要在两种格式间灵活切换:接收 OFD 格式的电子发票后转为 PDF 以便打印分发,或者将现有 PDF 合同转为 OFD 以满足政务平台的上传要求。
Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端直接完成 PDF 与 OFD 之间的双向转换,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
PDF 转 OFD 的核心在于将 PDF 文档中的页面内容、字体和图形元素重新编码为符合 OFD 标准的 XML 描述结构。Spire.PDF for JavaScript 通过 PdfDocument 对象的 SaveToFile 方法配合 FileFormat.OFD 枚举值,一键完成格式转换,无需手动处理底层格式差异。
function App() {
const convertToOFD = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将字体和 PDF 文件载入 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = '演示模板.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 定义为 OFD 格式的输出文件名
const outputFileName = '输出OFD.ofd';
// 保存为 OFD 格式
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.OFD });
doc.Close();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/ofd' });
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>Convert PDF To OFD</h1>
<button onClick={convertToOFD}>
Generate
</button>
</div>
);
}
export default App;
通过 SaveToFile 方法指定 FileFormat.OFD 生成的 OFD 文档

OFD 转 PDF 是政务电子文件分发场景中的常见需求。Spire.PDF for JavaScript 提供了 OfdConverter 组件,专门负责将 OFD 版式文档解析并导出为标准 PDF 文件,保持原始文档的版面布局和视觉效果不变。
function App() {
const convertOFDToPDF = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将字体和 OFD 文件载入 VFS
await window.spire.FetchFileToVFS('SIMKAI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = '电子发票.ofd';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 OfdConverter 对象并传入 OFD 文件路径
let converter = new pdfModule.OfdConverter(inputFileName);
// 定义为 PDF 格式的输出文件名
const outputFileName = '输出PDF.pdf';
// 转换为 PDF 格式
converter.ToPdf(outputFileName);
converter.Dispose();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.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;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Convert OFD To PDF</h1>
<button onClick={convertOFDToPDF}>
Generate
</button>
</div>
);
}
export default App;
通过 OfdConverter 转换后生成的 PDF 文档

原因:受密码保护的加密 PDF 无法直接通过 SaveToFile 保存为 OFD 格式,需要先解密文档。
解决:在加载 PDF 时通过 LoadFromFile 的第二个参数传入密码进行解密,然后再保存为 OFD:
// 加载带密码的 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName, "password");
// 保存为 OFD 格式
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.OFD });
doc.Close();
原因:OFD 文档依赖字体嵌入来保证跨平台显示一致性,如果输入 PDF 使用了未嵌入的字体且 VFS 中未加载对应字体文件,转换后可能出现文字显示异常。
解决:确保在调用转换前已将所需的 TrueType 字体文件(如 ARIALUNI.TTF)加载到 VFS 的 /Library/Fonts/ 目录下。ARIALUNI.TTF 包含了常用的中日韩文字符,是保证转换质量的首选字体。
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
数据标签是 Excel 图表中用于显示数据点详细信息的重要元素,它可以显示数值、系列名称、类别名称等内容。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成对 Excel 图表数据标签的样式设置,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。它提供了完整的 API 用于控制数据标签的显示内容、字体格式、数字格式、位置以及背景边框等外观属性。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
数据标签可以显示多种信息,包括数值、系列名称、类别名称和图例键等。通过 Spire.XLS for JavaScript,您可以灵活控制数据标签的显示内容,并自定义其字体样式,使图表信息更加清晰易读。具体操作步骤如下:
Workbook 对象并获取默认工作表。sheet.Charts.Add() 添加图表并设置图表类型。DataLabels 属性启用数据标签的显示内容(如数值、系列名称、类别名称)。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中设置图表数据标签的内容与字体:
function App() {
const setDataLabelContentAndFont = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 创建新工作簿并获取默认工作表
const workbook = new xlsModule.Workbook();
let sheet = workbook.Worksheets.get(0);
sheet.Name = "DataLabelDemo";
// 填入图表数据
sheet.Range.get("A1").Value = "Month";
sheet.Range.get("A2").Value = "Jan";
sheet.Range.get("A3").Value = "Feb";
sheet.Range.get("A4").Value = "Mar";
sheet.Range.get("A5").Value = "Apr";
sheet.Range.get("A6").Value = "May";
sheet.Range.get("A7").Value = "Jun";
sheet.Range.get("B1").Value = "Sales";
sheet.Range.get("B2").NumberValue = 25;
sheet.Range.get("B3").NumberValue = 18;
sheet.Range.get("B4").NumberValue = 8;
sheet.Range.get("B5").NumberValue = 13;
sheet.Range.get("B6").NumberValue = 22;
sheet.Range.get("B7").NumberValue = 28;
// 添加折线图并设置数据区域
let chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.LineMarkers });
chart.DataRange = sheet.Range.get("B1:B7");
chart.SeriesDataFromRange = false;
// 设置图表位置
chart.TopRow = 5;
chart.BottomRow = 26;
chart.LeftColumn = 2;
chart.RightColumn = 11;
// 配置图表标题
chart.ChartTitle = "Data Labels Demo";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
// 绑定分类标签
let cs1 = chart.Series.get(0);
cs1.CategoryLabels = sheet.Range.get("A2:A7");
// 设置数据标签的显示内容:显示数值、系列名称和类别名称
cs1.DataPoints.DefaultDataPoint.DataLabels.HasValue = true;
cs1.DataPoints.DefaultDataPoint.DataLabels.HasSeriesName = true;
cs1.DataPoints.DefaultDataPoint.DataLabels.HasCategoryName = true;
// 设置数据标签的分隔符
cs1.DataPoints.DefaultDataPoint.DataLabels.Delimiter = ". ";
// 自定义数据标签的字体样式
cs1.DataPoints.DefaultDataPoint.DataLabels.Size = 9;
cs1.DataPoints.DefaultDataPoint.DataLabels.Color = xlsModule.Color.get_Red();
cs1.DataPoints.DefaultDataPoint.DataLabels.FontName = "Calibri";
cs1.DataPoints.DefaultDataPoint.DataLabels.IsBold = true;
// 保存工作簿
const outputFileName = 'DataLabelContentAndFont.xlsx';
workbook.SaveToFile(outputFileName);
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Set Data Label Content and Font</h1>
<button onClick={setDataLabelContentAndFont}>
Generate
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 设置数据标签内容与字体后的效果

除了显示内容和字体样式外,数据标签的位置和外观也是图表美化的重要方面。Spire.XLS for JavaScript 支持通过 DataLabelPositionType 枚举调整数据标签的显示位置,并且可以为数据标签设置填充颜色、边框样式以及阴影效果。具体操作步骤如下:
Workbook 对象并加载包含图表的已有 Excel 文件。workbook.Worksheets.get() 获取工作表。sheet.Charts.get() 获取图表对象。DataLabels.Position 设置数据标签的位置。FrameFormat.Fill 为数据标签设置背景填充颜色。FrameFormat.Border 为数据标签设置边框颜色和样式。FrameFormat.Shadow 为数据标签添加阴影效果(类型、颜色、透明度、大小、模糊度、角度和距离)。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中调整图表数据标签的位置与外观:
function App() {
const setDataLabelPositionAndAppearance = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到虚拟文件系统(VFS)
let excelFileName = 'SampleChart.xlsx';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建新工作簿并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// 获取第一个工作表
let sheet = workbook.Worksheets.get(0);
// 获取第一个图表
let chart = sheet.Charts.get(0);
// 遍历所有数据系列,调整数据标签的位置和外观
for (let i = 0; i < chart.Series.Count; i++) {
let cs = chart.Series.get(i);
// 设置数据点标记样式和大小,使数据点更突出
cs.DataFormat.MarkerSize = 6;
cs.DataFormat.MarkerStyle = xlsModule.ChartMarkerType.Circle;
cs.DataFormat.MarkerForegroundColor = xlsModule.Color.get_Blue();
cs.DataFormat.MarkerBackgroundColor = xlsModule.Color.get_White();
let dataLabels = cs.DataPoints.DefaultDataPoint.DataLabels;
// 启用数值标签
dataLabels.HasValue = true;
// 设置数据标签位置
dataLabels.Position = xlsModule.DataLabelPositionType.Right;
// 设置数据标签的字体颜色和大小
dataLabels.Color = xlsModule.Color.get_Blue();
dataLabels.Size = 10;
// 设置粉红色填充背景
dataLabels.FrameFormat.Fill.FillType = xlsModule.ShapeFillType.SolidColor;
dataLabels.FrameFormat.ForeGroundColor = xlsModule.Color.get_Pink();
// 设置红色边框
dataLabels.FrameFormat.Border.Pattern = xlsModule.ChartLinePatternType.Solid;
dataLabels.FrameFormat.Border.Color = xlsModule.Color.get_Red();
// 设置黄色阴影效果
dataLabels.FrameFormat.Shadow.ShadowOuterType = xlsModule.XLSXChartShadowOuterType.OffsetDiagonalBottomLeft;
dataLabels.FrameFormat.Shadow.Color = xlsModule.Color.get_Yellow();
dataLabels.FrameFormat.Shadow.Transparency = 0;
dataLabels.FrameFormat.Shadow.Size = 10;
dataLabels.FrameFormat.Shadow.Blur = 2;
dataLabels.FrameFormat.Shadow.Angle = 45;
dataLabels.FrameFormat.Shadow.Distance = 8;
}
// 保存工作簿
const outputFileName = 'DataLabelPositionAndAppearance.xlsx';
workbook.SaveToFile(outputFileName);
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Set Data Label Position and Appearance</h1>
<button onClick={setDataLabelPositionAndAppearance}>
Generate
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 调整数据标签位置与外观后的效果

原因:DefaultDataPoint.DataLabels 作用于系列中所有数据点,无法单独控制单个数据点。
解决:通过 DataPoints.get(index) 获取指定数据点,再设置其标签:
// 修改第三个数据点的标签文字
chart.Series.get(0).DataPoints.get(2).DataLabels.Text = "峰值";
chart.Series.get(0).DataPoints.get(2).DataLabels.HasValue = false;
原因:数据标签显示的数字格式默认与单元格格式一致,但有时需要单独控制。
解决:使用 DataLabels.NumberFormat 属性自定义数字格式:
// 显示两位小数
dataLabels.NumberFormat = "0.00";
// 显示为百分比
dataLabels.NumberFormat = "0.0%";
// 显示为带货币符号的格式
dataLabels.NumberFormat = "¥#,##0";
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在日常办公中,经常需要在 Excel 电子表格和纯文本文件(TXT)之间进行数据交换。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成 Excel 与 TXT 格式的双向转换,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。它提供了灵活的 API 用于控制分隔符、编码格式等转换参数。
通过 Spire.XLS for JavaScript,您可以将 Excel 工作表中的数据导出为结构化的文本文件,也可以将带有分隔符的文本文件导入并创建为格式完整的 Excel 工作簿。这使得数据在不同应用程序之间的迁移变得更加便捷高效。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
将 Excel 数据导出为纯文本文件便于在其他应用程序中进一步处理或分析。通过 Spire.XLS for JavaScript,您可以将指定工作表中的内容保存为 TXT 文件,并自由选择字段分隔符和字符编码。具体操作步骤如下:
Workbook 对象并加载已有的 Excel 文件。workbook.Worksheets.get(index) 获取指定工作表。SaveToFile() 方法,指定输出文件名、分隔符和编码格式。下面是一个完整的代码示例,展示了在 React 中将 Excel 转换为 TXT:
function App() {
const convertToText = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到 VFS
await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);
// 创建工作簿对象并加载 Excel 文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: 'Sample.xlsx' });
// 获取第一个工作表
let sheet = workbook.Worksheets.get(0);
// 将工作表保存为 TXT 文件,使用空格作为分隔符,UTF-8 编码
const outputFileName = 'ExcelToTxt.txt';
sheet.SaveToFile({
fileName: outputFileName,
separator: " ",
encoding: xlsModule.Encoding.get_UTF8()
});
workbook.Dispose();
// 从 VFS 读取文件并触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { 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>将 Excel 转换为 TXT</h1>
<button onClick={convertToText}>
生成
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 将 Excel 转换为 TXT 文件

将带有分隔符的文本文件导入为 Excel 电子表格,可以充分利用 Excel 的格式化、计算和图表功能。Spire.XLS for JavaScript 支持通过读取文本文件内容并逐单元格写入工作簿来实现 TXT 到 Excel 的转换。转换过程中还可以设置标题行加粗等格式。具体操作步骤如下:
Workbook 对象,遍历数据列表并将数据逐行逐列写入工作表的单元格。AllocatedRange.AutoFitColumns() 自动调整列宽。下面是一个完整的代码示例,展示了在 React 中将 TXT 转换为 Excel:
function App() {
const convertToExcel = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 加载字体文件以确保文本正确渲染
await window.spire.FetchFileToVFS('ARIAL.TTF', '', `${process.env.PUBLIC_URL}font/`);
// 将 TXT 文件加载到 VFS
await window.spire.FetchFileToVFS('Sample.txt', '', `${process.env.PUBLIC_URL}data/`);
// 从 VFS 读取文本文件内容
const txtData = window.dotnetRuntime.Module.FS.readFile('Sample.txt');
const text = typeof txtData === 'string' ? txtData : new TextDecoder('utf-8').decode(txtData);
// 按行分割,兼容 \r\n 和 \n
const lines = text.trim().split(/\r?\n/);
// 解析每一行数据(尝试制表符分隔,若无效则尝试其他分隔符)
const data = [];
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
let cells = trimmed.split('\t');
if (cells.length === 1) {
cells = trimmed.split(/\s+/);
}
data.push(cells);
}
// 创建 Workbook 对象
const workbook = new xlsModule.Workbook();
// 获取第一张工作表
const sheet = workbook.Worksheets.get(0);
// 遍历数据列表中的行和列,写入单元格
for (let row = 0; row < data.length; row++) {
for (let col = 0; col < data[row].length; col++) {
const cell = sheet.get_Item(row + 1, col + 1);
cell.Value = data[row][col];
// 标题行加粗
if (row === 0) {
cell.Style.Font.IsBold = true;
}
}
}
// 设置自适应列宽
sheet.AllocatedRange.AutoFitColumns();
// 保存工作簿并释放资源
const outputFileName = 'TxtToExcel.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
workbook.Dispose();
// 从 VFS 读取文件并触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>将 TXT 转换为 Excel</h1>
<button onClick={convertToExcel}>
生成
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 将 TXT 转换为 Excel 文件

原因:本示例中的 TXT 文件使用了 UTF-8 编码。如果 TXT 文件采用了其他编码格式(如 GBK、GB2312 等),直接使用 TextDecoder('utf-8') 解码会导致乱码。
解决方案:根据 TXT 文件的实际编码,在 TextDecoder 的构造参数中指定对应的编码类型:
// UTF-8 编码
const text = new TextDecoder('utf-8').decode(txtData);
// GBK 编码
const text = new TextDecoder('gbk').decode(txtData);
// GB2312 编码
const text = new TextDecoder('gb2312').decode(txtData);
// UTF-16 编码
const text = new TextDecoder('utf-16').decode(txtData);
原因:TXT 文件可能使用不同的分隔符,如制表符(\t)、空格、逗号(,)、分号(;)等。如果分隔符选择不当,会导致数据解析错误。
解决方案:在 JavaScript 中,可通过修改 split() 方法的参数来指定不同的分隔符:
// 制表符分隔
let cells = trimmed.split('\t');
// 逗号分隔
let cells = trimmed.split(',');
// 分号分隔
let cells = trimmed.split(';');
// 正则表达式:按一个或多个空白字符(空格、制表符等)分隔
let cells = trimmed.split(/\s+/);
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在日常办公中,隐藏和取消隐藏 Excel 的行和列是一项常用的功能,它可以帮助您保护敏感信息、简化数据视图或临时隐藏不必要的数据。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成对 Excel 行和列的隐藏与取消隐藏操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。它提供了简洁的 API 用于控制行和列的可见性状态。
本文介绍四个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
隐藏特定的行和列可以在不影响数据完整性的前提下,让工作表更加清晰整洁。Spire.XLS for JavaScript 通过 HideRow() 和 HideColumn() 方法支持隐藏工作表中指定的单行或单列。具体操作步骤如下:
Workbook 对象并加载包含数据的已有 Excel 文件。worksheet.HideRow() 隐藏指定的行。worksheet.HideColumn() 隐藏指定的列。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中隐藏 Excel 中特定的行和列:
function App() {
const hideSpecificRowsAndColumns = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到虚拟文件系统(VFS)
let excelFileName = 'Sample.xlsx';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建工作簿对象并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
let sheet = workbook.Worksheets.get(0);
// 隐藏特定的行(第 4 行)
sheet.HideRow(4);
// 隐藏特定的列(第 2 列,即 B 列)
sheet.HideColumn(2);
// 保存工作簿
const outputFileName = 'HideSpecificRowsColumns.xlsx';
workbook.SaveToFile(outputFileName);
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Hide Specific Rows and Columns</h1>
<button onClick={hideSpecificRowsAndColumns}>
Generate
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 隐藏特定的行和列

当需要查看或编辑被隐藏的特定数据时,可以单独取消隐藏某一行或某一列。Spire.XLS for JavaScript 通过 ShowRow() 和 ShowColumn() 方法支持取消隐藏工作表中指定的单行或单列。具体操作步骤如下:
Workbook 对象并加载包含隐藏行列的已有 Excel 文件。sheet.ShowRow() 取消隐藏特定的行。sheet.ShowColumn() 取消隐藏特定的列。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中取消隐藏 Excel 中特定的行和列:
function App() {
const unhideSpecificRowsAndColumns = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到虚拟文件系统(VFS)
let excelFileName = 'HideSpecificRowsColumns.xlsx';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建工作簿对象并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// 获取第一个工作表
let sheet = workbook.Worksheets.get(0);
// 取消隐藏特定的行(第 4 行)
sheet.ShowRow(4);
// 取消隐藏特定的列(第 2 列,即 B 列)
sheet.ShowColumn(2);
// 保存工作簿
const outputFileName = 'UnhideSpecificRowsColumns.xlsx';
workbook.SaveToFile(outputFileName);
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Unhide Specific Rows and Columns</h1>
<button onClick={unhideSpecificRowsAndColumns}>
Generate
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 取消隐藏特定的行和列

当工作表中存在多个不需要显示的行或列时,逐个隐藏显然效率低下。Spire.XLS for JavaScript 支持通过循环调用 HideRow() 或 HideColumn() 一次性隐藏多个行和列,大大提升了操作效率。具体操作步骤如下:
Workbook 对象并加载包含数据的已有 Excel 文件。worksheet.HideRow() 一次性隐藏多个行。worksheet.HideColumn() 一次性隐藏多个列。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中一次性隐藏 Excel 中的多个行和列:
function App() {
const hideMultipleRowsAndColumns = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到虚拟文件系统(VFS)
let excelFileName = 'Sample.xlsx';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建工作簿对象并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
let sheet = workbook.Worksheets.get(0);
// 一次性隐藏多个行(第 6 行到第 10 行)
for (let i = 6; i <= 10; i++) {
sheet.HideRow(i);
}
// 一次性隐藏多个列(第 4 列到第 5 列,即 D 列到 E 列)
for (let j = 4; j <= 5; j++) {
sheet.HideColumn(j);
}
// 保存工作簿
const outputFileName = 'HideMultipleRowsColumns.xlsx';
workbook.SaveToFile(outputFileName);
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Hide Multiple Rows and Columns</h1>
<button onClick={hideMultipleRowsAndColumns}>
Generate
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 一次性隐藏多个行和列

要取消隐藏所有被隐藏的行和列,需要遍历工作表中的行和列,使用 GetRowIsHide() 和 GetColumnIsHide() 找到被隐藏的行和列,再调用 ShowRow() 和 ShowColumn() 取消隐藏。具体步骤如下:
Workbook 对象并加载 Excel 文件。GetRowIsHide() 找到被隐藏的行,用 ShowRow() 取消隐藏。GetColumnIsHide() 找到被隐藏的列,用 ShowColumn() 取消隐藏。SaveToFile() 保存结果文件。下面是一个完整的代码示例,展示了在 React 中取消隐藏 Excel 中所有被隐藏的行和列:
function App() {
const unhideAllRowsAndColumns = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到虚拟文件系统(VFS)
let excelFileName = 'HideMultipleRowsColumns.xlsx';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建工作簿对象并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// 获取第一个工作表
let sheet = workbook.Worksheets.get(0);
for (let i = 1; i <= sheet.Rows.length; i++) {
if (sheet.GetRowIsHide(i)) {
// 取消隐藏行
sheet.ShowRow(i);
}
}
for (let j = 1; j <= sheet.Columns.length; j++) {
if (sheet.GetColumnIsHide(j)) {
// 取消隐藏列
sheet.ShowColumn(j);
}
}
// 保存工作簿
const outputFileName = 'UnhideAllRowsColumns.xlsx';
workbook.SaveToFile(outputFileName);
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Unhide All Rows and Columns</h1>
<button onClick={unhideAllRowsAndColumns}>
Generate
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 取消隐藏所有被隐藏的行和列

解决:使用 GetRowIsHide() 和 GetColumnIsHide() 方法进行判断:
// 检查第 3 行是否被隐藏
let rowIsHidden = sheet.GetRowIsHide(3);
// 检查第 2 列(B 列)是否被隐藏
let columnIsHidden = sheet.GetColumnIsHide(2);
解决:隐藏行或列时,原始行高和列宽信息会被保留。当使用 ShowRow() 或 ShowColumn() 取消隐藏后,会自动恢复为原来的尺寸,无需额外设置。
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
Excel 文档属性(如标题、作者、类别等元数据)对于文件管理和信息检索至关重要。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成 Excel 文档属性的读取和删除操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。它提供了完整的 API 用于访问和管理 DocumentProperties(标准文档属性)和 CustomDocumentProperties(自定义文档属性)。
Spire.XLS 组件将文档属性分为两类:标准文档属性和自定义文档属性。标准文档属性是由 Excel 预定义的内置属性,如标题、主题、作者等;而自定义文档属性则是用户根据需求自行添加的名称-值对,可以包含文本、数字、日期或布尔值。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
读取文档属性是了解 Excel 文件元数据的第一步。通过 DocumentProperties 和 CustomDocumentProperties 集合,您可以轻松访问文件的所有属性信息。具体操作步骤如下:
Workbook 对象并加载已有的 Excel 文件。workbook.DocumentProperties 获取标准文档属性集合。DocumentProperties 集合,读取每个属性的名称和值。workbook.CustomDocumentProperties 获取自定义文档属性集合。CustomDocumentProperties 集合,读取每个自定义属性的名称和值。下面是一个完整的代码示例,展示了在 React 中读取 Excel 文档属性:
function App() {
const readDocumentProperties = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到 VFS
await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: 'Sample.xlsx' });
// 获取常规 Excel 属性
let properties1 = workbook.DocumentProperties;
let sb = [];
sb.push("Excel Properties:");
for (let i = 0; i < properties1.Count; i++) {
let name = properties1.get(i).Name;
let obj = properties1.get(i).Value;
let t = properties1.get(i).PropertyType;
let value = null;
if (t === xlsModule.PropertyType.Double) {
value = xlsModule.Double.Convert(obj).Value;
} else if (t === xlsModule.PropertyType.DateTime) {
// 将 OADate 转换为 JavaScript Date 并格式化为日期字符串
let oaDate = xlsModule.DateTime.Convert(obj).Value;
let jsDate = new Date((oaDate - 25569) * 86400 * 1000);
value = jsDate.toLocaleDateString();
} else if (t === xlsModule.PropertyType.Bool) {
value = xlsModule.Boolean.Convert(obj).Value;
} else if (
t === xlsModule.PropertyType.Int ||
t === xlsModule.PropertyType.Int32
) {
value = xlsModule.Int32.Convert(obj).Value;
} else {
value = xlsModule.String.Convert(obj).Value;
}
sb.push(name + ": " + String(value));
}
sb.push("");
// 获取自定义属性
let properties2 = workbook.CustomDocumentProperties;
sb.push("Custom Properties:");
for (let i = 0; i < properties2.Count; i++) {
let name = properties2.get(i).Name;
let t = properties2.get(i).PropertyType;
let obj = properties2.get(i).Value;
let value = null;
if (t === xlsModule.PropertyType.Double) {
value = xlsModule.Double.Convert(obj).Value;
} else if (t === xlsModule.PropertyType.DateTime) {
// 将 OADate 转换为 JavaScript Date 并格式化为日期字符串
let oaDate = xlsModule.DateTime.Convert(obj).Value;
let jsDate = new Date((oaDate - 25569) * 86400 * 1000);
value = jsDate.toLocaleDateString();
} else if (t === xlsModule.PropertyType.Bool) {
value = xlsModule.Boolean.Convert(obj).Value;
} else if (
t === xlsModule.PropertyType.Int ||
t === xlsModule.PropertyType.Int32
) {
value = xlsModule.Int32.Convert(obj).Value;
} else {
value = xlsModule.String.Convert(obj).Value;
}
sb.push(name + ": " + String(value));
}
// 将属性信息保存到文本文件
const outputFileName = 'DocumentProperties.txt';
window.dotnetRuntime.Module.FS.writeFile(outputFileName, sb.join("\n"));
workbook.Dispose();
// 从 VFS 读取文件并触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { 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>读取 Excel 文档属性</h1>
<button onClick={readDocumentProperties}>
生成
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 读取的文档属性

在某些场景下,您可能需要清除 Excel 文件中的敏感或过时的元数据信息。Spire.XLS for JavaScript 允许您通过简单的 API 调用删除标准和自定义文档属性。具体操作步骤如下:
Workbook 对象并加载已有的 Excel 文件。workbook.DocumentProperties 获取标准文档属性集合。workbook.CustomDocumentProperties 获取自定义文档属性集合。Remove() 方法删除每个自定义属性。下面是一个完整的代码示例,展示了在 React 中删除 Excel 文档属性:
function App() {
const deleteDocumentProperties = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将示例文件加载到 VFS
await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: 'Sample.xlsx' });
// 获取标准文档属性集合,并将各属性值设为空
let standardProperties = workbook.DocumentProperties;
standardProperties.Title = "";
standardProperties.Subject = "";
standardProperties.Manager = "";
standardProperties.Category = "";
standardProperties.Keywords = "";
standardProperties.Comments = "";
standardProperties.Author = "";
standardProperties.Company = "";
// 获取自定义文档属性集合,遍历并删除所有属性
let customProperties = workbook.CustomDocumentProperties;
for (let i = customProperties.Count - 1; i >= 0; i--) {
customProperties.Remove(customProperties.get(i).Name);
}
// 保存工作簿
const outputFileName = 'DeleteProperties.xlsx';
workbook.SaveToFile(outputFileName);
workbook.Dispose();
// 从 VFS 读取文件并触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>删除 Excel 文档属性</h1>
<button onClick={deleteDocumentProperties}>
生成
</button>
</div>
);
}
export default App;
使用 Spire.XLS for JavaScript 删除文档属性后的结果

原因:标准文档属性是 Excel 文件结构的一部分,每个属性都有固定的定义位置,无法从集合中移除。
解决方案:将标准属性的值设为空字符串以清除其内容,而非移除属性本身:
standardProperties.Title = "";
standardProperties.Author = "";
原因:直接使用 String.Convert() 处理日期或布尔值属性时,可能得到格式不符合预期的结果。
解决方案:根据 PropertyType 判断属性类型,并使用对应的类型转换方法:
if (t === xlsModule.PropertyType.DateTime) {
let oaDate = xlsModule.DateTime.Convert(obj).Value;
let jsDate = new Date((oaDate - 25569) * 86400 * 1000);
value = jsDate.toLocaleDateString();
} else if (t === xlsModule.PropertyType.Bool) {
value = xlsModule.Boolean.Convert(obj).Value;
}
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在 Web 应用中处理 Excel 文件时,复制数据并保留格式是常见的需求。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成 Excel 操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。它提供了完整的 API,支持复制行、列和单元格区域,同时保留原始样式、字体、颜色及其他格式。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
使用 Spire.XLS for JavaScript,您可以在同一工作表中或在不同工作表之间复制行,同时保留所有格式、公式和样式。通过 CopyRangeOptions 参数,您可以灵活设置复制选项,例如:复制所有格式、复制条件格式、复制数据验证,或者仅复制公式的结果值等等。这适用于需要复制结构化数据的场景,例如表头、汇总行或格式化模板。具体操作步骤如下:
Workbook 对象并加载已有的 Excel 文件。workbook.Worksheets.get() 获取源工作表和目标工作表。sheet.Rows[index] 获取要复制的行。sheet.Copy() 指定源行、目标工作表、目标行索引和 CopyRangeOptions.All,复制该行及其格式到目标工作表。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中复制 Excel 行:
function App() {
const copyRows = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将文件加载到虚拟文件系统(VFS)
let excelFileName = 'Copying.xls';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建新工作簿并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// 获取源工作表和目标工作表
let sheet1 = workbook.Worksheets.get(0);
let sheet2 = workbook.Worksheets.get(1);
// 获取要复制的行
let row = sheet1.Rows[0];
// 将该行及所有格式复制到目标工作表
sheet1.Copy({ sourceRange: row, destRange: sheet2.Rows[0], copyOptions: xlsModule.CopyRangeOptions.All });
// 将源行的列宽复制到目标行的相应单元格
let columns = sheet1.Columns.length;
for (let i = 0; i < columns; i++) {
let columnWidth = row.Columns[i].ColumnWidth;
sheet2.Rows[0].Columns[i].ColumnWidth = columnWidth;
}
// 保存工作簿
const outputFileName = 'CopyRows_out.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>复制 Excel 行</h1>
<button onClick={copyRows}>
生成
</button>
</div>
);
}
export default App;
复制行结果

使用 Spire.XLS for JavaScript 复制列同样简单。您可以在同一工作表中复制列,或将其复制到另一个工作表,所有单元格样式、数字格式和数据都会被保留。通过 CopyRangeOptions 参数,您可以灵活设置复制选项。这对于重新组织电子表格布局或复制数据结构非常有用。具体操作步骤如下:
Workbook 对象并加载已有的 Excel 文件。sheet.Columns[index] 获取要复制的列。sheet.Copy() 指定源列、目标工作表、目标列索引和 CopyRangeOptions.All,复制该列及其格式到目标工作表。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中复制 Excel 列:
function App() {
const copyColumns = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将文件加载到虚拟文件系统(VFS)
let excelFileName = 'Copying.xls';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建新工作簿并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// 获取源工作表和目标工作表
let sheet1 = workbook.Worksheets.get(0);
let sheet2 = workbook.Worksheets.get(1);
// 获取要复制的列
let column = sheet1.Columns[0];
// 将该列及所有格式复制到目标工作表
sheet1.Copy({ sourceRange: column, destRange: sheet2.Columns[0], copyOptions: xlsModule.CopyRangeOptions.All });
// 将源列的列宽和行高复制到目标列的相应单元格
sheet2.Columns[0].ColumnWidth = column.ColumnWidth;
let rows = column.Rows.length;
for (let i = 0; i < rows; i++) {
let rowHeight = column.Rows[i].RowHeight;
sheet2.Columns[0].Rows[i].RowHeight = rowHeight;
}
// 保存工作簿
const outputFileName = 'CopyColumns_out.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>复制 Excel 列</h1>
<button onClick={copyColumns}>
生成
</button>
</div>
);
}
export default App;
复制列结果

除了复制整行和整列外,Spire.XLS for JavaScript 还提供了 CellRange.Copy() 方法,支持复制特定单元格或单元格区域并保留所有格式。这为您提供了更细粒度的控制,能够精确选择要复制的单元格。您可以在同一工作表中或跨工作表复制单元格区域。具体操作步骤如下:
Workbook 对象并加载已有的 Excel 文件。sheet.Range.get() 获取源单元格区域和目标单元格区域。sourceRange.Copy() 指定目标区域和 CopyRangeOptions.All,复制源单元格区域及其格式到目标单元格区域。SaveToFile() 保存工作簿为 Excel 文件。下面是一个完整的代码示例,展示了在 React 中复制 Excel 单元格:
function App() {
const copyCells = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将文件加载到虚拟文件系统(VFS)
let excelFileName = 'Copying.xls';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建新工作簿并加载已有文件
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// 获取源工作表和目标工作表
let sheet1 = workbook.Worksheets.get(0);
let sheet2 = workbook.Worksheets.get(1);
// 获取源单元格区域和目标单元格区域
let range1 = sheet1.Range.get("A1:E7");
let range2 = sheet2.Range.get("A1:E7");
// 将源单元格区域及其格式复制到目标单元格区域
range1.Copy({ destRange: range2, copyOptions: xlsModule.CopyRangeOptions.All });
// 将源单元格区域的行高和列宽复制到目标单元格区域
for (let i = 0; i < range1.Rows.length; i++) {
let row = range1.Rows[i];
for (let j = 0; j < row.Columns.length; j++) {
let column = row.Columns[j];
range2.Rows[i].Columns[j].ColumnWidth = column.ColumnWidth;
range2.Rows[i].RowHeight = row.RowHeight;
}
}
// 保存工作簿
const outputFileName = 'CopyCells.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
workbook.Dispose();
// 从 VFS 读取文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>复制 Excel 单元格</h1>
<button onClick={copyCells}>
生成
</button>
</div>
);
}
export default App;
复制单元格结果

原因:默认情况下,Copy() 方法会覆盖目标位置的现有数据,而不会自动合并或保留原有内容。
解决:如果希望保留目标位置的原有数据,请选择一个空白区域作为目标范围,或在复制前检查目标区域是否为空。也可以先备份目标区域的数据,再执行复制操作。
原因:默认 CopyRangeOptions.All 会复制公式本身,而有时只需要公式的计算结果值,不需要保留公式逻辑。
解决:使用 CopyRangeOptions.OnlyCopyFormulaValue 选项,仅复制公式的计算结果值,而非公式本身:
sourceRange.Copy({ destRange: destRange, copyOptions: xlsModule.CopyRangeOptions.OnlyCopyFormulaValue });
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
Spire.Office for Java 11.7.0 已上线。在该版本中,Spire.Doc for Java 支持通过 isSVG 属性检测 SVG 图片;Spire.XLS for Java支持单元格区域转 HTML 功能;Spire.PDF for Python支持签名域中文本自动适配;Spire.Presentation for Java支持转换 PPT 到纯 HTML 格式。此外,本次更新还成功修复了多个已知问题。更多详情如下。
https://www.e-iceblue.cn/Downloads/Spire-Office-JAVA.html
新功能:
Document doc1 = ConvertUtil.GetNewEngineDocument();
doc1.loadFromFile(inputFile_1);
String[] name1 = new String[]{"DJG_Black_Book", "DJG_Repairs_Expense", "DJG_Sale_Amount", "DJG_Dealer_Payment", "DJG_Auction_Fees"};
String[] value1 = new String[]{"20,000.00", "2,000.00", "13,500.00", "1,000.00", "500.00"};
doc1.getMailMerge().execute(name1, value1);
doc1.isUpdateFields(true);
Document doc2 = ConvertUtil.GetNewEngineDocument();
doc2.loadFromFile(inputFile_2);
String[] name2 = new String[]{"DJG_Black_Book", "DJG_Repairs_Expense", "DJG_Sale_Amount", "DJG_Dealer_Payment", "DJG_Auction_Fees"};
String[] value2 = new String[]{"50,000.00", "5,000.00", "3,500.00", "1,000.00", "200.00"};
doc2.getMailMerge().execute(name2, value2);
doc2.isUpdateFields(true);
CompareOptions options = new CompareOptions();
options.setCompareMoves(true);
options.setIgnoreCaseChanges(true);
options.setIgnoreComments(true);
options.setIgnoreFields(true);
options.setIgnoreFootnotes(true);
options.setIgnoreTables(true);
options.setIgnoreTextboxes(true);
doc1.compare(doc2, "user", new Date(), options);
doc1.saveToFile(outputFile, FileFormat.Docx_2013);
doc1.close();
doc2.close();
Document doc = ConvertUtil.GetNewEngineDocument();
Section section = doc.addSection();
section.setTextDirection(TextDirection.Right_To_Left);
Paragraph titlePara = section.addParagraph();
titlePara.appendText("===== FarEastLayout Two-Lines-in-One Full Scenario Test =====\n\n");
titlePara.appendText("\n\n1. Basic Two-Lines-in-One: ");
// Basic Two-Lines-in-One Combine=true, no brackets, no vertical layout
Paragraph p1 = section.addParagraph();
TextRange farEastLayout = p1.appendText("Basic Two-Lines-in-One: One Two Three Four");
farEastLayout.getCharacterFormat().setFontSize(12);
farEastLayout.getCharacterFormat().setFontNameFarEast("Songti");
FarEastLayout layout1 = new FarEastLayout();
layout1.setCombine(true); // Two-Lines-in-One
farEastLayout.getCharacterFormat().setFarEastLayout(layout1);
// Two-Lines-in-One + various bracket styles
Paragraph p1Title = section.addParagraph();
p1Title.appendText("\n\n2. Two-Lines-in-One + Different Brackets: ");
for (CombineBrackets bracket : CombineBrackets.values()) {
Paragraph pTmp = section.addParagraph();
TextRange rt = pTmp.appendText("Bracket Type " + bracket.name() + ": A B C D");
rt.getCharacterFormat().setFontSize(12);
rt.getCharacterFormat().setFontNameFarEast("Songti");
FarEastLayout layoutTmp = new FarEastLayout();
layoutTmp.setCombine(true);
layoutTmp.setCombineBrackets(bracket);
rt.getCharacterFormat().setFarEastLayout(layoutTmp);
}
doc.saveToFile(outputFile, FileFormat.Docx);
doc.close();
DocPicture picture=(DocPicture) object;if(picture.isSVG()){
byte[] svgBytes = picture.getImageBytes();
Files.write(Paths.get(outputFile),svgBytes);
}
问题修复:
新功能:
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
HTMLOptions.Default.isSaveFreezedPanes(true);
wb.saveToFile(outputFile, FileFormat.HTML);
wb.dispose();
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
MarkdownOptions markdownOptions = new MarkdownOptions();
markdownOptions.isSavePicInRelativePath(true);
wb.saveToMarkdown(outputFile, markdownOptions);
wb.dispose();
sheet.getRange().get("G7").setFormula("=BYROW(B7:F7, LAMBDA(row, AVERAGE(row)))");
sheet.getRange().get("B8").setFormula("=BYCOL(B2:B7, LAMBDA(col, AVERAGE(col)))");
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
MarkdownOptions markdownOptions = new MarkdownOptions();
markdownOptions.isSaveHyperlinkAsRef(true);
wb.saveToMarkdown(outputFile, markdownOptions);
wb.dispose();
StringBuilder sb = new StringBuilder();
Workbook workbook = new Workbook();
workbook.loadFromFile(inputFile);
Worksheet sheet = workbook.getWorksheets().get(0);
CellRange cell = sheet.getRange().get("A1:B3");
sb.append(cell.getHtmlString());
sheet.getRange().get("C4").setFormula("=XMATCH(\"王五\", A2:A5)");
Workbook workbook = new Workbook();
workbook.loadFromFile(inputFile);
Worksheet sheet = workbook.getWorksheets().get(0);
EnumSet<CopyRangeOptions> options = EnumSet.of(CopyRangeOptions.Transpose, CopyRangeOptions.All);
sheet.getRange().get("D1").setText("A1:C4置换到D2:G3:");
sheet.getRange().get("A1:C4").copy(sheet.getRange().get("D2:G3"), options);
sheet.getRange().get("D4").setText("A1:B5置换到D5:");
sheet.getRange().get("A1:B5").copy(sheet.getRange().get("D5"), options);
options = EnumSet.of(CopyRangeOptions.Transpose, CopyRangeOptions.CopyStyles);
sheet.getRange().get("D9").setText("A10置换到D10:");
sheet.getRange().get("A10").copy(sheet.getRange().get("D10"), options);
sheet.getRange().get("D11").setText("A11:B11置换到D12:");
sheet.getRange().get("A11:B11").copy(sheet.getRange().get("D12"), options);
options = EnumSet.of(CopyRangeOptions.Transpose, CopyRangeOptions.CopyConditionalFormats);
sheet.getRange().get("D16").setText("B17:B20置换到D17:");
sheet.getRange().get("B17:B20").copy(sheet.getRange().get("D17"), options);
options = EnumSet.of(CopyRangeOptions.Transpose, CopyRangeOptions.CopyStyles);
sheet.getRange().get("D19").setText("B17:B20置换到D20:");
sheet.getRange().get("B17:B20").copy(sheet.getRange().get("D20"), options);
options = EnumSet.of(CopyRangeOptions.Transpose);
sheet.getRange().get("D22").setText("B17:B20置换到D23:");
sheet.getRange().get("B17:B20").copy(sheet.getRange().get("D23"), options);
workbook.saveToFile(outputFile);
sheet.dispose();
workbook.dispose();
Workbook workbook = new Workbook();
Worksheet sheet = workbook.getWorksheets().get(0);
XlsRange range = (XlsRange)sheet.getRange().get("A1");
range.insertEmbedCheckBox();
range.setEmbedCheckBoxCheckState(true);
workbook.saveToFile(outputFile);
workbook.dispose();
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
Worksheet worksheet = wb.getWorksheets().get(0);
// Access the collection of scenarios in the worksheet
XlsScenarioCollection scenarios = worksheet.getScenarios();
//Initialize list objects with different values for scenarios
List<Object> currentChangePercentage_Values = new ArrayList<Object>() {{ add(0.23); add(0.8); add(1.1); add(0.5); add(0.35); add(0.2); }};
List<Object> increasedChangePercentage_Values = new ArrayList<Object>() {{ add(0.45); add(0.56); add(0.9); add(0.5); add(0.58); add(0.43); }};
List<Object> decreasedChangePercentage_Values = new ArrayList<Object>() {{ add(0.3); add(0.2); add(0.5); add(0.3); add(0.5); add(0.23); }};
List<Object> currentQuantity_Values = new ArrayList<Object>() {{ add(1500); add(3000); add(5000); add(4000); add(500); add(4000); }};
List<Object> increasedQuantity_Values = new ArrayList<Object>() {{ add(1000); add(5000); add(4500); add(3900); add(10000); add(8900); }};
List<Object> decreasedQuantity_Values = new ArrayList<Object>() {{ add(1000); add(2000); add(3000); add(3000); add(300); add(4000); }};
//Add scenarios in the worksheet with different values for the same cells
scenarios.add("Current % of Change", worksheet.getRange().get("F5:F10"), currentChangePercentage_Values);
scenarios.add("Increased % of Change", worksheet.getRange().get("F5:F10"), increasedChangePercentage_Values);
scenarios.add("Decreased % of Change", worksheet.getRange().get("F5:F10"), decreasedChangePercentage_Values);
scenarios.add("Current Quantity", worksheet.getRange().get("D5:D10"), currentQuantity_Values);
scenarios.add("Increased Quantity", worksheet.getRange().get("D5:D10"), increasedQuantity_Values);
scenarios.add("Decreased Quantity", worksheet.getRange().get("D5:D10"), decreasedQuantity_Values);
//Saving the workbook
wb.saveToFile(outputFile, ExcelVersion.Version2013);
wb.dispose();
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
Worksheet worksheet = wb.getWorksheets().get(0);
// Access the collection of scenarios in the worksheet
XlsScenarioCollection scenarios = worksheet.getScenarios();
XlsScenario scenario1 = scenarios.get(0);
XlsScenario scenario2 = scenarios.get(1);
//Modify the scenario
scenario1.setVariableCells(worksheet.getRange().get("A1:A5"), scenario2.getValues());
CellRange sourceCell = worksheet.getRange().get("B1:B5");
scenario2.setVariableCells(sourceCell, scenario2.getValues());
scenario1.show();
scenario2.show();
//Saving the workbook
wb.saveToFile(outputFile, ExcelVersion.Version2013);
wb.dispose();
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
Worksheet worksheet = wb.getWorksheets().get(0);
// Access the collection of scenarios in the worksheet
XlsScenarioCollection scenarios = worksheet.getScenarios();
//delete the scenario
scenarios.removeScenarioAt(0);
scenarios.removeScenarioByName("two");
String content = "";
content += "Count:" + scenarios.getCount() + "\n";
content += "ContainsScenario:" + scenarios.containsScenario("two") + "\n";
content += "ContainsScenario:" + scenarios.containsScenario("one") + "\n";
TestUtil.writeAllText(outputFile, content);
//Saving the workbook
wb.dispose();
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
Worksheet worksheet = wb.getWorksheets().get(0);
// Access the collection of scenarios in the worksheet
XlsScenarioCollection scenarios = worksheet.getScenarios();
//Initialize list objects with different values for scenarios
List<Object> currentChangePercentage_Values = new ArrayList<Object>() {{ add(0.23); add(0.8); add(1.1); add(0.5); add(0.35); add(0.2); }};
List<Object> increasedChangePercentage_Values = new ArrayList<Object>() {{ add(0.45); add(0.56); add(0.9); add(0.5); add(0.58); add(0.43); }};
List<Object> decreasedChangePercentage_Values = new ArrayList<Object>() {{ add(0.3); add(0.2); add(0.5); add(0.3); add(0.5); add(0.23); }};
List<Object> currentQuantity_Values = new ArrayList<Object>() {{ add(1500); add(3000); add(5000); add(4000); add(500); add(4000); }};
List<Object> increasedQuantity_Values = new ArrayList<Object>() {{ add(1000); add(5000); add(4500); add(3900); add(10000); add(8900); }};
List<Object> decreasedQuantity_Values = new ArrayList<Object>() {{ add(1000); add(2000); add(3000); add(3000); add(300); add(4000); }};
//Add scenarios in the worksheet with different values for the same cells
scenarios.add("Current % of Change", worksheet.getRange().get("F5:F10"), currentChangePercentage_Values);
scenarios.add("Increased % of Change", worksheet.getRange().get("F5:F10"), increasedChangePercentage_Values);
scenarios.add("Decreased % of Change", worksheet.getRange().get("F5:F10"), decreasedChangePercentage_Values);
scenarios.add("Current Quantity", worksheet.getRange().get("D5:D10"), currentQuantity_Values);
scenarios.add("Increased Quantity", worksheet.getRange().get("D5:D10"), increasedQuantity_Values);
scenarios.add("Decreased Quantity", worksheet.getRange().get("D5:D10"), decreasedQuantity_Values);
//Create Summary
worksheet.getScenarios().summary(worksheet.getRange().get("L7"));
//Saving the workbook
wb.saveToFile(outputFile, ExcelVersion.Version2013);
wb.dispose();
Workbook wb = new Workbook();
wb.loadFromFile(inputFile);
Worksheet worksheet1 = wb.getWorksheets().get(0);
Worksheet worksheet2 = wb.getWorksheets().get(1);
//Merge the scenario
worksheet1.getScenarios().merge(worksheet2);
//Saving the workbook
wb.saveToFile(outputFile, ExcelVersion.Version2013);
wb.dispose();
Workbook workbook = new Workbook();
workbook.loadFromFile(inputFile);
workbook.saveToFile(outputFile, FileFormat.Json);
workbook.dispose();
问题修复:
新功能:
Presentation ppt = new Presentation();
ppt.loadFromFile(inputFile);
ppt.getSaveToHtmlOption().setPureHtml(true);
ppt.saveToFile(outputFile, FileFormat.HTML);
ppt.dispose();
问题修复:
问题修复:
优化:
Spire.Cloud 11.7.3 现已发布。本次更新共新增了16个功能点,重点补齐了冻结窗格、显示比例、网格线与标题控制等视图交互能力,让浏览器端表格操作更贴近桌面版 Excel 体验。详细新增功能见下表。
| 模块 | 分组 | 功能点 |
|---|---|---|
| 文件 | 信息 | 设置文档属性 |
| 页面布局 | 工作表选项 | 网格线 |
| 标题 | ||
| 公式 | 函数库 | 自动求和 |
| 视图 | 显示/隐藏 | 行、列标题 |
| 垂直、水平网格线 | ||
| 新建工作表 | ||
| 工作表选项卡 | ||
| 显示比例 | 显示比例 | |
| 100% | ||
| 缩放选定区域 | ||
| 窗口 | 冻结首行 | |
| 冻结首列 | ||
| 冻结最后行 | ||
| 冻结最后列 | ||
| 右键工作表 | 标签 | 设置标签 |
Spire.Doc for Java 14.7.4 现已正式发布。该版本新增 isSVG 属性,支持判断图片是否为 SVG 格式,同时修复了 Word 文档保存、对比、克隆以及 Word 转 PDF 过程中存在的多个问题。详情如下。
新功能:
DocPicture picture=(DocPicture) object;if(picture.isSVG()){
byte[] svgBytes = picture.getImageBytes();
Files.write(Paths.get(outputFile),svgBytes);
}
问题修复:
Spire.Office 11.7.0 已正式发布。该版本新增了一些功能,如Spire.XLS 新增属性避免因页眉/页脚文本过长而触发异常;Spire.Presentation 支持保存宏文件以及管理 VBA 模块,包括添加和删除 VBA 模块。除此之外,一些在操作Excel、PDF和PPT文档时出现的问题也得以成功解决。更多新功能及问题修复详情如下。
该版本涵盖了最新版的Spire.Doc、Spire.PDF、Spire.XLS、Spire.Presentation、Spire.DataExport、Spire.Barcode、Spire.DocViewer、Spire.PDFViewer、Spire.OfficeViewer、Spire.Email。
https://www.e-iceblue.cn/Downloads/Spire-Office-NET.html
新功能:
workbook.ConverterSetting.ValidateHeaderFooterLength = false;
问题修复:
新功能:
Presentation ppt = new Presentation();
//添加VBA项目到文档
IVbaProject vbaProject = ppt.VbaProject;
vbaProject.Name = "SampleVBAMacro";
vbaProject.CodePage = 936; //设置编码,支持中文
IVbaModule vbaModule = vbaProject.Modules.Add("SampleModule", VbaModuleType.Module);
vbaModule.SourceCode = @"
Sub ExampleMacro()
' 声明变量
Dim pptPres As Object
Dim pptSlide As Object
Dim pptShape As Object
' 设置引用到当前演示文稿
Set pptPres = ActivePresentation
' 遍历所有幻灯片
Dim i As Integer
For i = 1 To pptPres.Slides.Count
Set pptSlide = pptPres.Slides(i)
' 为每张幻灯片添加标题文本 (msoTextOrientationHorizontal = 1)
Set pptShape = pptSlide.Shapes.AddTextbox(1, 50, 50, 600, 50)
pptShape.TextFrame.TextRange.Text = ""幻灯片 "" & i & "" - 由宏自动生成""
With pptShape.TextFrame.TextRange.Font
.Bold = -1 ' msoTrue = -1
.Size = 24
.Color.RGB = RGB(0, 102, 204)
End With
Next i
' 显示完成消息
MsgBox ""宏执行完成!已处理 "" & pptPres.Slides.Count & "" 张幻灯片。"", vbInformation, ""操作提示""
End Sub";
ppt.SaveToFile("result.pptm", FileFormat.Pptm);
ppt.Dispose();
//按名称移除模块
Presentation ppt1 = new Presentation();
ppt1.LoadFromFile(inputFile);
IVbaModule firstModule = ppt1.VbaProject.Modules[0];
sb.AppendLine("【按名称移除】");
sb.AppendLine("模块名称:" + firstModule.Name);
sb.AppendLine("模块类型:" + firstModule.Type);
sb.AppendLine("删除前模块数量:" + ppt1.VbaProject.Modules.Count);
ppt1.VbaProject.Modules.Remove(firstModule.Name);
sb.AppendLine("删除后模块数量:" + ppt1.VbaProject.Modules.Count);
ppt1.SaveToFile("result1.pptm", FileFormat.Pptm);
ppt1.Dispose();
//按索引移除模块
Presentation ppt2 = new Presentation();
ppt2.LoadFromFile(inputFile);
sb.AppendLine("【按索引移除(0)】");
sb.AppendLine("删除前模块数量:" + ppt2.VbaProject.Modules.Count);
ppt2.VbaProject.Modules.RemoveAt(0);
sb.AppendLine("删除后模块数量:" + ppt2.VbaProject.Modules.Count);
ppt2.SaveToFile("result2.pptm", FileFormat.Pptm);
ppt2.Dispose();
//按VbaModule对象移除模块(强制转换为具体类型)
Presentation ppt3 = new Presentation();
ppt3.LoadFromFile(inputFile);
IVbaModule moduleObj = ppt3.VbaProject.Modules[4];
VbaModule vbaModule = (VbaModule)moduleObj;
sb.AppendLine("【按对象移除】");
sb.AppendLine("模块名称:" + vbaModule.Name);
sb.AppendLine("模块类型:" + vbaModule.Type);
sb.AppendLine("删除前模块数量:" + ppt3.VbaProject.Modules.Count);
ppt3.VbaProject.Modules.Remove(vbaModule);
sb.AppendLine("删除后模块数量:" + ppt3.VbaProject.Modules.Count);
ppt3.SaveToFile("result3.pptm", FileFormat.Pptm);
ppt3.Dispose();
//清空所有模块
Presentation ppt4 = new Presentation();
ppt4.LoadFromFile(inputFile);
sb.AppendLine("【清空Clear】");
sb.AppendLine("删除前模块数量:" + ppt4.VbaProject.Modules.Count);
ppt4.VbaProject.Modules.Clear();
sb.AppendLine("删除后模块数量:" + ppt4.VbaProject.Modules.Count);
ppt4.SaveToFile("result4.pptm", FileFormat.Pptm);
问题修复:
问题修复:
问题修复: