如何使用 JavaScript 创建 Excel 文件(XLSX/XLS)
JavaScript 可以直接在浏览器中生成 Excel 工作簿。借助 Spire.XLS for JavaScript,你可以创建工作簿、添加工作表、写入数据和公式、应用格式,并将结果保存为 XLSX 或 XLS 文件——全部在客户端完成,无需安装 Microsoft Excel。
本教程从一个基础的 XLSX 工作簿开始,逐步引入带类型的单元格写入、公式、格式化、多工作表、浏览器下载、CSV 转换以及 XLS 格式输出。
快速导航:
安装并初始化 Spire.XLS for JavaScript
Spire.XLS for JavaScript 包含在 spire.office 包中,与 Spire.PDF、Spire.Doc 和 Spire.Presentation 一起发布:
初始化运行时需要两步导入。第一步启动共享的 .NET WebAssembly 宿主机,第二步注册电子表格 API:
1 2 3 4 5 6
| const common = await import('/node_modules/spire.office/spire.common.js'); await common.initializeWasm();
await import('/node_modules/spire.office/spire.xls.js');
|
Spire.*.Wasm.zip 压缩包和 _framework 文件夹必须能从站点根目录访问。运行时基于文档 URL 解析这些文件,而不是基于执行导入的模块路径,因此在 Vite 或 Create React App 项目中需要将它们放在 public/ 目录下。React 项目中常见的 process.env.PUBLIC_URL 前缀是 Create React App 的约定,并非浏览器标准——如果未使用 CRA,请根据构建工具调整基础路径。如果压缩包缺失,浏览器会输出 WebAssembly.compile(): expected magic word——这是因为开发服务器用 index.html 响应了压缩包请求。
之后所有操作都通过一个全局对象进行:
1
| const xls = window.spirexls;
|
本教程使用的当前包版本中,电子表格 API 通过 window.spirexls 暴露。在运行时初始化完成后即可使用该全局对象。旧版本通过 window.wasmModule.spirexls 暴露;如果使用不同的包版本,请检查可用的全局变量。
现在可以开始生成 Excel 文件了。
在 JavaScript 中创建基础 Excel 文件
我们来构建一份销售报表。创建工作簿、添加工作表、将产品数据写入单元格,然后保存为 XLSX 文件并自动下载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| async function createExcelFile() { const xls = window.spirexls; if (!xls) { console.error('Spire.XLS 尚未初始化'); return; }
const workbook = new xls.Workbook(); workbook.Worksheets.Clear(); const sheet = workbook.Worksheets.Add("销售报表");
const data = [ ["产品", "数量", "单价"], ["笔记本电脑", 10, 999.99], ["无线鼠标", 50, 24.99], ["机械键盘", 30, 59.99], ["显示器", 15, 329.99] ];
sheet.Range.get("A1:C5").Style.Font.FontName = "等线";
for (let row = 0; row < data.length; row++) { for (let col = 0; col < data[row].length; col++) { const cell = sheet.Range.get({ row: row + 1, column: col + 1 }); if (typeof data[row][col] === "string") { cell.Text = data[row][col]; } else { cell.NumberValue = data[row][col]; } } }
const fileName = "SalesReport.xlsx"; workbook.SaveToFile({ fileName: fileName, version: xls.ExcelVersion.Version2016 });
const fileData = window.dotnetRuntime.Module.FS.readFile(fileName); const blob = new Blob([fileData], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = fileName; a.click(); URL.revokeObjectURL(url);
workbook.Dispose(); }
|
调用 createExcelFile() 即可得到包含四行产品数据和一行表头的 SalesReport.xlsx。整个流程很简洁:创建工作簿 → 写入数据 → 保存 → 下载。
后续各节将在此基础上扩展。每个代码片段都假定在 createExcelFile() 中工作簿和工作表已创建之后添加。

向 Excel 单元格写入不同数据类型
Excel 区分文本、数字、日期和布尔值。类型使用不当会导致排序失效、公式报错、数字以文本形式显示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const sheet = workbook.Worksheets.get(0);
sheet.Range.get("A1").Text = "产品名称";
sheet.Range.get("B1").NumberValue = 999.99;
const dateCell = sheet.Range.get("C1"); dateCell.DateTimeValue = new Date(Date.UTC(2025, 2, 15)); dateCell.NumberFormat = "yyyy-mm-dd";
sheet.Range.get("D1").BooleanValue = true;
|
最常见的错误是写 cell.Text = "999.99" 而非 cell.NumberValue = 999.99。打开文件时数值看起来一样,但 Excel 会将其视为文本——无法求和、求平均或按数值排序。始终用 NumberValue 写数字、DateTimeValue 写日期、BooleanValue 写布尔值。
日期还需要一个额外注意点。DateTimeValue 保留的是 JavaScript Date 所表示的 UTC 时间点。用本地午夜创建日期在某些时区下会导致显示的日期偏移;若要保留特定的日历日期,请使用 Date.UTC()。
为 Excel 工作表添加公式
公式让生成的文件成为真正的电子表格,而不只是数据堆砌。我们来添加一个「金额」列计算每行的 数量 × 单价,并在底部添加合计行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| sheet.Range.get({ row: 1, column: 4 }).Text = "金额";
for (let i = 2; i <= 5; i++) { sheet.Range.get({ row: i, column: 4 }).Formula = `=B${i}*C${i}`; }
sheet.Range.get({ row: 6, column: 1 }).Text = "合计"; sheet.Range.get({ row: 6, column: 2 }).Formula = "=SUM(B2:B5)"; sheet.Range.get({ row: 6, column: 4 }).Formula = "=SUM(D2:D5)";
workbook.CalculateAllValue();
|
当需要生成的工作簿包含公式的计算结果时,在保存前调用 workbook.CalculateAllValue()。这对于依赖缓存值而非打开时重新计算的查看器或应用程序很有用。
如需深入了解 Excel 函数和公式操作,请参阅在 React 中使用 JavaScript 在 Excel 工作表中插入或读取函数和公式。
格式化生成的 Excel 文件
只有原始数据的表格能用,但格式化的表格才能传达信息。我们把销售报表变成一份可以直接发给同事的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const header = sheet.Range.get("A1:D1"); header.Style.Font.IsBold = true; header.Style.Font.Size = 12; header.Style.Color = xls.Color.get_LightSkyBlue();
for (let i = 2; i <= 5; i++) { sheet.Range.get({ row: i, column: 3 }).NumberFormat = "¥#,##0.00"; sheet.Range.get({ row: i, column: 4 }).NumberFormat = "¥#,##0.00"; }
[26, 10, 12, 12].forEach((width, i) => { sheet.Columns.get(i).ColumnWidth = width; });
const usedRange = sheet.Range.get("A1:D6"); usedRange.Borders.LineStyle = xls.LineStyleType.Thin; usedRange.Borders.Color = xls.Color.get_LightSteelBlue();
|
有两个细节值得注意。sheet.Columns.get(i) 和 sheet.Rows.get(i) 是 0 基索引并使用 get 方法,与其他集合暴露的 get_Item 不同。此外,在测试的浏览器环境中,AutoFitColumn 需要的字体在 WebAssembly 沙箱中不可用,因此显式设置 ColumnWidth 更可靠。
最终效果:粗体蓝色表头、货币格式的价格、宽度合适的列以及整洁的边框。
如需了解单元格边框的详细设置方法,请参阅在 React 中使用 JavaScript 添加或删除单元格边框。
在 Excel 工作簿中创建多个工作表
实际报表很少只放在一个工作表上。销售报表可能需要在第一个标签页放摘要,第二个放产品明细,第三个放月度分解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| workbook.Worksheets.Clear(); const summarySheet = workbook.Worksheets.Add("汇总"); const productsSheet = workbook.Worksheets.Add("产品明细"); const monthlySheet = workbook.Worksheets.Add("月度数据");
productsSheet.Range.get("A1").Text = "产品"; productsSheet.Range.get("B1").Text = "数量"; productsSheet.Range.get("C1").Text = "单价"; productsSheet.Range.get("D1").Text = "金额";
const products = [ ["笔记本电脑", 10, 999.99], ["无线鼠标", 50, 24.99], ["机械键盘", 30, 59.99], ["显示器", 15, 329.99] ];
for (let i = 0; i < products.length; i++) { const row = i + 2; productsSheet.Range.get({ row: row, column: 1 }).Text = products[i][0]; productsSheet.Range.get({ row: row, column: 2 }).NumberValue = products[i][1]; productsSheet.Range.get({ row: row, column: 3 }).NumberValue = products[i][2]; productsSheet.Range.get({ row: row, column: 4 }).Formula = `=B${row}*C${row}`; }
summarySheet.Range.get("A1").Text = "销售汇总"; summarySheet.Range.get("A1").Style.Font.IsBold = true; summarySheet.Range.get("A2").Text = "产品总数"; summarySheet.Range.get("B2").NumberValue = 4; summarySheet.Range.get("A3").Text = "销售总额"; summarySheet.Range.get("B3").Formula = "=SUM(产品明细!D2:D5)";
productsSheet.Range.get("A1:D5").Style.Font.FontName = "等线"; summarySheet.Range.get("A1:B3").Style.Font.FontName = "等线";
|
每次 Worksheets.Add(name) 都会按调用顺序返回新创建的工作表,因此标签页顺序与代码顺序一致。注意跨表公式:汇总工作表中的 =SUM(产品明细!D2:D5) 引用了产品明细工作表的 金额 列。Excel 在文件打开时自动处理这类引用——无需额外代码。

如需了解更多工作表管理操作——添加、删除和重排工作表,请参阅在 React 中使用 JavaScript 添加、删除、移动 Excel 工作表。
在浏览器中保存并下载 XLSX 文件
工作簿准备好之后,Spire.XLS 会将其保存到 WebAssembly 虚拟文件系统中。然后读取文件数据、转换为 Blob 并触发下载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| workbook.SaveToFile({ fileName: "Report.xlsx", version: xls.ExcelVersion.Version2016 });
const fileData = window.dotnetRuntime.Module.FS.readFile("Report.xlsx"); const blob = new Blob([fileData], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "Report.xlsx"; a.click(); URL.revokeObjectURL(url);
workbook.Dispose();
|
务必在下载后调用 workbook.Dispose() 释放内存——尤其是在用户可能在一个会话中生成多个文件的应用中。工作簿本身驻留在 WebAssembly 堆中,直到你显式释放,而该堆不会被浏览器的垃圾回收器自动回收。
需要 React 集成或 HTML 表格导出?请参阅我们的如何在 JavaScript 和 React 中下载/导出 Excel 文件指南。
综合示例:格式化销售报表
前面各节分别处理了工作簿的一个方面。下面将它们整合到一个函数中:一个带斑马纹和货币格式的工作表、由公式驱动的收入和占比列、一个柱形图,以及一个汇总数据的第二个工作表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
async function createExcelReport() { const xls = window.spirexls; if (!xls) throw new Error('Spire.XLS 尚未就绪');
const products = [ ['星辰 14 轻薄本', 42, 6499.0], ['云雀 无线鼠标', 380, 149.0], ['磐石 机械键盘', 165, 399.0], ['流光 27 英寸 4K 显示器', 74, 2699.0], ['山海 USB-C 扩展坞', 210, 799.0], ['静默 主动降噪耳机', 128, 1299.0], ]; const FIRST = 5; const TOTAL = FIRST + products.length;
const wb = new xls.Workbook(); wb.Worksheets.Clear(); const sheet = wb.Worksheets.Add('销售报表');
const at = (a) => sheet.Range.get(a); const cell = (row, col) => sheet.Range.get({ row: row, column: col }); const paint = (a, colour) => { at(a).Style.Color = colour; };
[34, 9, 13, 14, 9].forEach((w, i) => { sheet.Columns.get(i).ColumnWidth = w; }); sheet.Rows.get(0).RowHeight = 34; sheet.Rows.get(1).RowHeight = 20; sheet.Rows.get(2).RowHeight = 8; sheet.Rows.get(3).RowHeight = 24;
at('A1:E1').Merge(); cell(1, 1).Text = '销售报表 — 2026 年第三季度'; paint('A1:E1', xls.Color.get_DarkBlue()); at('A1:E1').Style.Font.Color = xls.Color.get_White(); at('A1:E1').Style.Font.IsBold = true; at('A1:E1').Style.Font.Size = 15; at('A1:E1').Style.VerticalAlignment = xls.VerticalAlignType.Center;
at('A2:E2').Merge(); cell(2, 1).Text = '区域:华东 · 周期:2026 年 7–9 月 · 金额单位:人民币(元)'; paint('A2:E2', xls.Color.get_DarkBlue()); at('A2:E2').Style.Font.Color = xls.Color.get_LightSteelBlue(); at('A2:E2').Style.Font.Size = 9.5; at('A2:E2').Style.VerticalAlignment = xls.VerticalAlignType.Center;
['产品', '销量', '单价', '销售额', '占比'].forEach((label, i) => { cell(4, i + 1).Text = label; }); paint('A4:E4', xls.Color.get_LightSteelBlue()); at('A4:E4').Style.Font.Color = xls.Color.get_DarkBlue(); at('A4:E4').Style.Font.IsBold = true; at('A4:E4').Style.Font.Size = 10.5; at('A4:E4').Style.HorizontalAlignment = xls.HorizontalAlignType.Center; at('A4:E4').Style.VerticalAlignment = xls.VerticalAlignType.Center;
products.forEach(([name, units, price], i) => { const r = FIRST + i; cell(r, 1).Text = name; cell(r, 2).NumberValue = units; cell(r, 3).NumberValue = price; cell(r, 4).Formula = `=B${r}*C${r}`; cell(r, 5).Formula = `=D${r}/$D$${TOTAL}`; sheet.Rows.get(r - 1).RowHeight = 20; if (i % 2) paint(`A${r}:E${r}`, xls.Color.get_WhiteSmoke()); });
cell(TOTAL, 1).Text = '合计'; [2, 4, 5].forEach((col) => { const letter = String.fromCharCode(64 + col); cell(TOTAL, col).Formula = `=SUM(${letter}${FIRST}:${letter}${TOTAL - 1})`; }); paint(`A${TOTAL}:E${TOTAL}`, xls.Color.get_LightSkyBlue()); at(`A${TOTAL}:E${TOTAL}`).Style.Font.IsBold = true; sheet.Rows.get(TOTAL - 1).RowHeight = 22;
at(`B${FIRST}:B${TOTAL}`).NumberFormat = '#,##0'; at(`C${FIRST}:D${TOTAL}`).NumberFormat = '¥#,##0.00'; at(`E${FIRST}:E${TOTAL}`).NumberFormat = '0.0%';
const table = at(`A4:E${TOTAL}`); table.Borders.LineStyle = xls.LineStyleType.Thin; table.Borders.Color = xls.Color.get_LightSteelBlue(); at(`A${TOTAL}:E${TOTAL}`).Borders.get_Item(xls.BordersLineType.EdgeTop).LineStyle = xls.LineStyleType.Medium;
const chart = sheet.Charts.Add(); chart.ChartType = xls.ExcelChartType.ColumnClustered; chart.LeftColumn = 6; chart.TopRow = 3; chart.RightColumn = 13; chart.BottomRow = 21; const serie = chart.Series.Add(); serie.CategoryLabels = at(`A${FIRST}:A${TOTAL - 1}`); serie.Values = at(`D${FIRST}:D${TOTAL - 1}`); serie.Name = '销售额'; chart.ChartTitleArea.Text = '各产品销售额'; chart.HasLegend = false; chart.PrimaryValueAxis.NumberFormat = '¥#,##0';
sheet.FreezePanes(FIRST, 1); sheet.GridLinesVisible = false; sheet.TabColor = xls.Color.get_DarkBlue();
const summary = wb.Worksheets.Add('汇总'); summary.Columns.get(0).ColumnWidth = 26; summary.Columns.get(1).ColumnWidth = 18; summary.Rows.get(0).RowHeight = 30; summary.Rows.get(1).RowHeight = 18; summary.Rows.get(3).RowHeight = 22;
const band = (a, text, size) => { summary.Range.get(a).Merge(); summary.Range.get(a.split(':')[0]).Text = text; summary.Range.get(a).Style.Color = xls.Color.get_DarkBlue(); summary.Range.get(a).Style.Font.Color = xls.Color.get_White(); summary.Range.get(a).Style.Font.IsBold = true; summary.Range.get(a).Style.Font.Size = size; summary.Range.get(a).Style.VerticalAlignment = xls.VerticalAlignType.Center; }; band('A1:B1', '报表摘要', 14); band('A2:B2', '销售报表 · 2026 年第三季度', 9.5);
['指标', '数值'].forEach((label, i) => { summary.Range.get({ row: 4, column: i + 1 }).Text = label; }); summary.Range.get('A4:B4').Style.Color = xls.Color.get_LightSteelBlue(); summary.Range.get('A4:B4').Style.Font.Color = xls.Color.get_DarkBlue(); summary.Range.get('A4:B4').Style.Font.IsBold = true;
[ ['销售总额', "='销售报表'!D" + TOTAL, '¥#,##0.00'], ['销售数量', "='销售报表'!B" + TOTAL, '#,##0'], ['平均单价', `='销售报表'!D${TOTAL}/'销售报表'!B${TOTAL}`, '¥#,##0.00'], ].forEach(([label, formula, format], i) => { summary.Range.get({ row: 5 + i, column: 1 }).Text = label; const value = summary.Range.get({ row: 5 + i, column: 2 }); value.Formula = formula; value.NumberFormat = format; value.Style.HorizontalAlignment = xls.HorizontalAlignType.Right; if (i % 2) summary.Range.get(`A${5 + i}:B${5 + i}`).Style.Color = xls.Color.get_WhiteSmoke(); });
summary.Range.get('A8').Text = '报表日期'; const reportDate = summary.Range.get('B8'); reportDate.DateTimeValue = new Date(Date.UTC(2026, 8, 28)); reportDate.NumberFormat = 'yyyy-mm-dd'; reportDate.Style.HorizontalAlignment = xls.HorizontalAlignType.Right;
const kpis = summary.Range.get('A4:B8'); kpis.Borders.LineStyle = xls.LineStyleType.Thin; kpis.Borders.Color = xls.Color.get_LightSteelBlue(); summary.GridLinesVisible = false; summary.TabColor = xls.Color.get_LightSteelBlue();
at(`A1:E${TOTAL}`).Style.Font.FontName = '等线'; summary.Range.get('A1:B8').Style.Font.FontName = '等线';
wb.CalculateAllValue(); const fileName = 'SalesReport.xlsx'; wb.SaveToFile({ fileName: fileName, version: xls.ExcelVersion.Version2016 });
const fileData = window.dotnetRuntime.Module.FS.readFile(fileName); const blob = new Blob([fileData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', }); const url = URL.createObjectURL(blob); Object.assign(document.createElement('a'), { href: url, download: fileName }).click(); URL.revokeObjectURL(url);
wb.Dispose(); }
|
布局由数据驱动。将 products 数组替换为你自己 API 的响应,其余部分——合计、占比、图表范围、汇总数据——全部继续正常工作,因为它们都是通过公式或派生范围表达的,而非硬编码的值。

如需了解更多图表类型和配置选项,请参阅在 React 中使用 JavaScript 创建 Excel 图表。
从 CSV 数据创建 Excel 文件
可以将 CSV 文件中的表格数据加载到工作表中,然后保存为 XLSX。生成的工作簿可以进一步格式化或添加公式和额外的工作表:
1 2 3 4 5 6 7 8 9 10 11
|
const csv = "产品,数量,单价\n笔记本电脑,10,999.99\n无线鼠标,50,24.99\n机械键盘,30,59.99"; window.dotnetRuntime.Module.FS.writeFile("data.csv", new TextEncoder().encode(csv));
workbook.LoadFromFile("data.csv", ","); workbook.SaveToFile({ fileName: "ConvertedFromCSV.xlsx", version: xls.ExcelVersion.Version2016 });
|
导入的工作表以文件名命名(data),因此 Worksheets.get(0) 即可获取。
分隔符是必需的第二个参数。单独调用 LoadFromFile("data.csv") 会被拒绝并返回 This is not a structured storage file,因为单参数重载期望的是 .xlsx 或 .xls 等结构化格式,不会自动识别 CSV。
还有第二个陷阱:CSV 导入器会将每个字段都写为文本。数量列到达时是 "10" 而非 10,这意味着无法求和或按数值排序——正是前面描述的问题。在保存前转换需要的列:
1 2 3 4 5 6 7 8 9 10 11 12
| const csvSheet = workbook.Worksheets.get(0);
for (let row = 2; row <= 4; row++) { [2, 3].forEach((column) => { const cell = csvSheet.Range.get({ row: row, column: column }); if (cell.Text !== "") { cell.NumberValue = Number(cell.Text); } }); }
|
如需了解 CSV 与 Excel 格式之间的完整转换指南,请参阅我们的在 React 中使用 JavaScript 将 Excel 转换为 CSV 或将 CSV 转换为 Excel 教程。
创建 XLS 格式文件
如果应用需要生成旧版 .xls 格式而非 .xlsx,修改版本参数即可:
1 2 3 4
| workbook.SaveToFile({ fileName: "Report.xls", version: xls.ExcelVersion.Version97to2003 });
|
枚举成员是 Version97to2003——不存在 Version97。图表请保留在 XLSX 中;测试发现 XLS 写入器在需要图表字体度量时会失败。
XLSX(Excel 2007+)是新建应用的推荐格式。XLS(Excel 97–2003)仅在需要向后兼容时使用。
常见问题
window.wasmModule 为 undefined。 旧示例从 window.wasmModule.spirexls 读取电子表格 API。当前版本直接将其安装在 window.spirexls 上,wasmModule 保持 undefined,因此首次访问就会抛出异常。请改用 window.spirexls。
WASM 模块未初始化。 如果 window.spirexls 为 undefined,说明运行时尚未加载完成。显示加载指示器,等待初始化完成后再执行 Excel 操作。
自动调整列宽抛出字体错误。 AutoFitColumn 和 AutoFitRow 需要系统字体来测量文本,而 WebAssembly 沙箱中没有可用字体。它们会以 Cannot found font(Arial) installed on the system. 失败。请用 sheet.Columns.get(i).ColumnWidth 计算或硬编码列宽。
数字存储为文本。 使用 cell.Text = "100" 而非 cell.NumberValue = 100 会破坏排序和计算。这是开发者在用 JavaScript 写 Excel 文件时最常遇到的问题,CSV 导入也会自动触发——始终用 NumberValue 写入数值数据。
出现”Evaluation Warning”工作表。 使用未授权的评估版本时,Spire.XLS 会在保存的工作簿中添加一个评估工作表。该工作表在每次保存时都会重新创建,因此以编程方式移除并不可靠。请应用许可证密钥来防止此问题。
长时间运行应用中的内存泄漏。 在每个生成周期后调用 workbook.Dispose()。在单页应用中,未释放的工作簿会累积内存并导致性能逐渐下降。
FAQ
JavaScript 能在不安装 Microsoft Excel 的情况下创建 Excel 文件吗?
可以。Spire.XLS for JavaScript 通过 WebAssembly 完全在浏览器中运行,生成 XLSX 文件不需要 Microsoft Excel 或服务端 Office 安装。
JavaScript 能直接在浏览器中创建 XLSX 文件吗?
可以。所有电子表格操作都在客户端完成。文件保存到虚拟文件系统后,以 Blob 形式下载——不需要后端服务器。
XLS 和 XLSX 有什么区别?
XLSX(Excel 2007 及更高版本)是现代的基于 XML 的格式,推荐用于新建应用。XLS(Excel 97–2003)是旧版二进制格式,适用于旧系统兼容场景。
总结
用 JavaScript 创建 Excel 文件不需要后端服务器或 Microsoft Excel。借助 Spire.XLS for JavaScript,你可以在浏览器中从零构建工作簿、写入带类型的数据、添加公式、应用格式,并将数据组织到多个工作表中。
从上面的基础示例开始,随着需求增长再逐步加入公式和格式。如需 React 专用集成和 HTML 表格导出,请参阅我们的专门的导出教程。