
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:
npm i spire.office
Для запуска среды требуется два импорта. Первый запускает общий хост .NET WebAssembly; второй регистрирует API для работы с электронными таблицами:
// 1. Boot the shared runtime once per page.
const common = await import('/node_modules/spire.office/spire.common.js');
await common.initializeWasm();
// 2. Load the spreadsheet engine — this is what creates window.spirexls.
await import('/node_modules/spire.office/spire.xls.js');
Архивы Spire.*.Wasm.zip и папка _framework должны быть доступны из корня сайта. Среда выполнения разрешает их относительно URL документа, а не относительно модуля, выполнившего импорт, поэтому в проекте Vite или Create React App они должны находиться в public/. Префикс process.env.PUBLIC_URL, показанный в настройках на основе React, является соглашением Create React App, а не стандартом браузера — настройте базовый путь в соответствии с вашим инструментом сборки, если вы не используете CRA. Если архивы отсутствуют, браузер выводит в консоль WebAssembly.compile(): expected magic word — сервер разработки ответил на запрос архива с помощью index.html.
Затем всё завязано на один глобальный объект:
const xls = window.spirexls;
В текущей конфигурации пакета, используемой в этом руководстве, API для работы с электронными таблицами предоставляется через window.spirexls. Используйте этот глобальный объект после инициализации среды выполнения. В более старых версиях он был доступен как window.wasmModule.spirexls; если вы работаете с другой версией пакета, проверьте, какой глобальный объект доступен.
Теперь вы готовы создавать файлы Excel.
Создание базового файла Excel на JavaScript
Давайте создадим отчёт о продажах. Мы создадим книгу, добавим рабочий лист, запишем данные о продуктах в ячейки и сохраним результат в виде файла XLSX, который автоматически загрузится.
async function createExcelFile() {
const xls = window.spirexls;
if (!xls) {
console.error('Spire.XLS is not initialized.');
return;
}
// A fresh Workbook() already contains three blank worksheets, so clear them
// and add the single sheet this report needs.
const workbook = new xls.Workbook();
workbook.Worksheets.Clear();
const sheet = workbook.Worksheets.Add("Sales Report");
// Sample data: product sales
const data = [
["Product", "Quantity", "Price"],
["Laptop", 10, 999.99],
["Mouse", 50, 24.99],
["Keyboard", 30, 59.99],
["Monitor", 15, 329.99]
];
// Write data to cells
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];
}
}
}
// Save to the virtual file system, read the bytes, download, then dispose
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 различает текст, числа, даты и логические значения. Неправильное определение типа приводит к файлам, в которых нарушается сортировка, формулы возвращают ошибки, а числа отображаются как текст.
const sheet = workbook.Worksheets.get(0);
// Text — for labels, names, descriptions
sheet.Range.get("A1").Text = "Product Name";
// Number — for anything you'll calculate, sort, or filter
sheet.Range.get("B1").NumberValue = 999.99;
// Date — a real DateTimeValue plus a display format
const dateCell = sheet.Range.get("C1");
dateCell.DateTimeValue = new Date(Date.UTC(2025, 2, 15));
dateCell.NumberFormat = "yyyy-mm-dd";
// Boolean — use BooleanValue, not text
sheet.Range.get("D1").BooleanValue = true;
Самая распространённая ошибка? Запись cell.Text = "999.99" вместо cell.NumberValue = 999.99. Значение выглядит идентично при открытии файла, но Excel обрабатывает его как текст — вы не можете суммировать, усреднять или сортировать его численно. Всегда используйте NumberValue для чисел, DateTimeValue для дат и BooleanValue для логических значений.
Даты требуют одной дополнительной меры предосторожности. DateTimeValue сохраняет момент UTC, представленный JavaScript-объектом Date. Создание даты с местной полуночью может поэтому сдвинуть отображаемый день в некоторых часовых поясах; используйте Date.UTC(), когда вы хотите сохранить конкретную календарную дату.
Добавление формул на рабочий лист Excel
Формулы превращают созданный файл в настоящую электронную таблицу, а не просто в набор данных. Давайте добавим столбец Total, который вычисляет Quantity × Price для каждой строки, а также общий итог внизу:
// Add "Total" header
sheet.Range.get({ row: 1, column: 4 }).Text = "Total";
// Per-row formula: Total = Quantity × Price
for (let i = 2; i <= 5; i++) {
sheet.Range.get({ row: i, column: 4 }).Formula = `=B${i}*C${i}`;
}
// Grand total row
sheet.Range.get({ row: 6, column: 1 }).Text = "Total";
sheet.Range.get({ row: 6, column: 2 }).Formula = "=SUM(B2:B5)";
sheet.Range.get({ row: 6, column: 4 }).Formula = "=SUM(D2:D5)";
// Evaluate the formulas once, so their results are written into the file.
workbook.CalculateAllValue();
Вызывайте workbook.CalculateAllValue() перед сохранением, когда вам нужно, чтобы созданная книга содержала вычисленные результаты формул. Это полезно для программ просмотра или приложений, которые полагаются на кэшированные значения вместо пересчёта формул при открытии.
Для получения полного руководства по функциям Excel и операциям с формулами см. Вставка или чтение функций и формул в рабочих листах Excel с помощью JavaScript в React.
Форматирование созданного файла Excel
Электронная таблица с необработанными данными работает, но отформатированная таблица передаёт информацию. Давайте превратим наш отчёт о продажах во что-то, что вы действительно отправили бы заинтересованному лицу:
// Bold, colored header row
const header = sheet.Range.get("A1:D1");
header.Style.Font.IsBold = true;
header.Style.Font.Size = 12;
header.Style.Color = xls.Color.get_LightSkyBlue();
// Currency format for Price and Total columns
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";
}
// Set column widths explicitly
[26, 10, 12, 12].forEach((width, i) => {
sheet.Columns.get(i).ColumnWidth = width;
});
// Clean borders
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 более надёжна.
Результат: жирный синий заголовок, цены в денежном формате, столбцы правильного размера и чистые границы.
Для получения подробных рекомендаций по размерам строк и столбцов см. Установка высоты строки и ширины столбца в Excel с помощью JavaScript в React.
Создание нескольких рабочих листов в книге Excel
Настоящие отчёты редко помещаются на одном листе. Отчёт о продажах может содержать сводку на первой вкладке, сведения о продуктах на второй и помесячную разбивку на третьей.
workbook.Worksheets.Clear();
const summarySheet = workbook.Worksheets.Add("Summary");
const productsSheet = workbook.Worksheets.Add("Products");
const monthlySheet = workbook.Worksheets.Add("Monthly Data");
// Products sheet — write actual data so cross-sheet formulas work
productsSheet.Range.get("A1").Text = "Product";
productsSheet.Range.get("B1").Text = "Quantity";
productsSheet.Range.get("C1").Text = "Price";
productsSheet.Range.get("D1").Text = "Total";
const products = [
["Laptop", 10, 999.99],
["Mouse", 50, 24.99],
["Keyboard", 30, 59.99],
["Monitor", 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}`;
}
// Summary sheet with cross-sheet reference
summarySheet.Range.get("A1").Text = "Sales Summary";
summarySheet.Range.get("A1").Style.Font.IsBold = true;
summarySheet.Range.get("A2").Text = "Total Products";
summarySheet.Range.get("B2").NumberValue = 4;
summarySheet.Range.get("A3").Text = "Total Revenue";
summarySheet.Range.get("B3").Formula = "=SUM(Products!D2:D5)";
Каждый вызов Worksheets.Add(name) возвращает только что созданный лист в порядке вызовов, поэтому порядок вкладок соответствует порядку в коде. Обратите внимание на формулу между листами: =SUM(Products!D2:D5) на листе Summary ссылается на столбец Total на листе Products. Excel обрабатывает это автоматически при открытии файла — дополнительный код не требуется.

Подробнее об управлении рабочими листами — добавлении, удалении и изменении порядка листов — см. Добавление, удаление и перемещение рабочих листов Excel с помощью JavaScript в React.
Сохранение и загрузка файла XLSX в браузере
Когда ваша книга готова, Spire.XLS сохраняет её в виртуальную файловую систему WebAssembly. Затем вы читаете данные файла, преобразуете их в Blob и запускаете загрузку:
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-таблиц? Ознакомьтесь с нашим руководством по загрузке и экспорту файлов Excel в JavaScript и React.
Собираем всё вместе: форматированный отчёт о продажах
Приведённые выше фрагменты создают книгу по частям. Здесь они собраны в одну функцию: оформленный рабочий лист с чередующейся заливкой строк и денежными форматами, столбцы выручки и доли на основе формул, гистограмма и второй рабочий лист, который суммирует числа.
/**
* Build a formatted sales report workbook in the browser and download it as
* SalesReport.xlsx.
*
* The layout is driven by `products` below — swap it for form input, an API
* response or component state and nothing else needs to change.
*/
async function createExcelReport() {
// spire.office 11.7.0 exposes Spire.XLS as `window.spirexls`. Older builds
// hung it off `window.wasmModule.spirexls`; that global no longer exists.
const xls = window.spirexls;
if (!xls) throw new Error('Spire.XLS is not ready yet');
// [product, units sold, unit price] — revenue and share are derived by formula
const products = [
['Atlas 14 Ultrabook', 42, 1249.0],
['Orbit Wireless Mouse', 380, 24.99],
['Vertex Mechanical Keyboard', 165, 89.5],
['Lumen 27 4K Monitor', 74, 429.0],
['Halo USB-C Dock', 210, 139.0],
['Pulse ANC Headset', 128, 199.0],
];
const FIRST = 5; // first data row
const TOTAL = FIRST + products.length; // total row
const wb = new xls.Workbook();
wb.Worksheets.Clear();
const sheet = wb.Worksheets.Add('Sales Report');
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;
};
// ── Sizing ── explicit widths (AutoFitColumn is unreliable in the WASM sandbox)
[34, 9, 13, 14, 9].forEach((w, i) => {
sheet.Columns.get(i).ColumnWidth = w;
});
sheet.Rows.get(0).RowHeight = 34; // title
sheet.Rows.get(1).RowHeight = 20; // subtitle
sheet.Rows.get(2).RowHeight = 8; // spacer
sheet.Rows.get(3).RowHeight = 24; // header
// ── Title band ── merge first, then style the whole merged area
at('A1:E1').Merge();
cell(1, 1).Text = 'Sales Report — Q3 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 = 'Region: West · Period: 1 Jul – 30 Sep 2026 · Amounts in USD';
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;
// ── Header row ───────────────────────────────────────────────────────────
['Product', 'Units', 'Unit Price', 'Revenue', 'Share'].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;
// ── Data rows ── numbers go in as NumberValue, never as text
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}`; // share of the grand total
sheet.Rows.get(r - 1).RowHeight = 20;
if (i % 2) paint(`A${r}:E${r}`, xls.Color.get_WhiteSmoke()); // zebra banding
});
// ── Total row ────────────────────────────────────────────────────────────
cell(TOTAL, 1).Text = 'Total';
[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;
// ── Number formats and borders ───────────────────────────────────────────
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;
// ── Chart ── build the series by hand (DataRange would mix units)
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 = 'Revenue';
chart.ChartTitleArea.Text = 'Revenue by product';
chart.HasLegend = false;
chart.PrimaryValueAxis.NumberFormat = '$#,##0';
// ── Sheet chrome ──
sheet.FreezePanes(FIRST, 1);
sheet.GridLinesVisible = false;
sheet.TabColor = xls.Color.get_DarkBlue();
// ── Second worksheet: cross-sheet roll-up ──
const summary = wb.Worksheets.Add('Summary');
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', 'Executive Summary', 14);
band('A2:B2', 'Sales Report · Q3 2026', 9.5);
['Metric', 'Value'].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;
[
['Total revenue', "='Sales Report'!D" + TOTAL, '$#,##0.00'],
['Units shipped', "='Sales Report'!B" + TOTAL, '#,##0'],
['Average unit price', `='Sales Report'!D${TOTAL}/'Sales Report'!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();
});
// Date — use Date.UTC to avoid timezone shift
summary.Range.get('A8').Text = 'Report date';
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();
// ── Save, then release ──
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(); // free the WASM heap — one workbook per generation cycle
}
Макет следует за данными. Замените массив products на ответ от вашего собственного API, и всё остальное — итоги, процентные доли, диапазон диаграммы, сводка — продолжит работать, потому что всё это выражено формулами или производными диапазонами, а не жёстко заданными значениями.

Для получения информации о других типах диаграмм и параметрах настройки см. Создание диаграмм Excel с помощью JavaScript в React.
Создание файла Excel из данных CSV
Вы можете загрузить табличные данные из файла CSV на рабочий лист и сохранить результат в формате XLSX. Полученную книгу затем можно отформатировать или расширить с помощью формул и дополнительных рабочих листов:
// The library reads from its own virtual file system, so the CSV has to be
// there before you can load it — written from a string here, from the bytes of
// a File object in a real application.
const csv = "Product,Quantity,Price\nLaptop,10,999.99\nMouse,50,24.99\nKeyboard,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, что означает, что его нельзя суммировать или сортировать численно — именно та проблема, которая была описана ранее в этом руководстве. Преобразуйте нужные столбцы перед сохранением:
const csvSheet = workbook.Worksheets.get(0);
// The importer leaves every field as text — coerce each numeric column.
// Columns 2 and 3 hold Quantity and Price; both arrive as "10" and "999.99".
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 см. наш учебник по преобразованию CSV в Excel.
Создание файла XLS вместо XLSX
Если вашему приложению нужно создавать устаревший формат .xls вместо .xlsx, измените параметр версии:
workbook.SaveToFile({
fileName: "Report.xls",
version: xls.ExcelVersion.Version97to2003
});
Член перечисления — Version97to2003 — Version97 не существует. Оставляйте диаграммы в XLSX; протестированный модуль записи XLS даёт сбой, когда требуются метрики шрифта диаграммы.
XLSX (Excel 2007+) — рекомендуемый формат для новых приложений. XLS (Excel 97–2003) необходим только при необходимости обратной совместимости.
Распространённые проблемы
window.wasmModule не определён. В старых примерах API для работы с электронными таблицами читался из window.wasmModule.spirexls. В текущих выпусках он устанавливается непосредственно в window.spirexls, а wasmModule остаётся неопределённым, поэтому самое первое обращение вызывает исключение. Вместо этого проверяйте window.spirexls.
Модуль WASM не инициализирован. Если window.spirexls не определён, среда выполнения ещё не завершила загрузку. Покажите индикатор загрузки и дождитесь завершения инициализации, прежде чем пытаться выполнять любые операции с Excel.
Автоподбор выдаёт ошибку шрифта. AutoFitColumn и AutoFitRow нуждаются в системном шрифте для измерения текста, а в песочнице WebAssembly его нет. Они завершаются с ошибкой Cannot found font(Arial) installed on the system. Вычислите или жёстко задайте ширину столбцов с помощью sheet.Columns.get(i).ColumnWidth.
Числа, сохранённые как текст. Использование cell.Text = "100" вместо cell.NumberValue = 100 нарушает сортировку и вычисления. Это самая распространённая проблема, с которой сталкиваются разработчики при записи файлов Excel на JavaScript, и импорт CSV автоматически её вызывает — всегда используйте NumberValue для числовых данных.
Появляется лист "Evaluation Warning". При использовании оценочной сборки без действующей лицензии Spire.XLS добавляет оценочный лист в сохраняемую книгу. Этот лист создаётся заново при каждом сохранении, поэтому его программное удаление не является надёжным обходным путём. Примените лицензионный ключ, чтобы предотвратить его появление.
Утечки памяти в долго работающих приложениях. Вызывайте workbook.Dispose() после каждого цикла создания. В одностраничных приложениях неосвобождённые книги накапливают память и со временем снижают производительность.
Часто задаваемые вопросы
Может ли JavaScript создавать файлы Excel без Microsoft Excel?
Да. Spire.XLS for JavaScript полностью работает в браузере через WebAssembly. Для создания файлов XLSX не требуется установка Microsoft Excel или серверного Office.
Может ли JavaScript создавать файлы XLSX непосредственно в браузере?
Да. Все операции с электронными таблицами выполняются на стороне клиента. Файл сохраняется в виртуальную файловую систему, а затем загружается как Blob — серверная часть не требуется.
В чём разница между XLS и XLSX?
XLSX (Excel 2007 и более поздние версии) — современный формат на основе XML, рекомендуемый для новых приложений. XLS (Excel 97–2003) — устаревший двоичный формат, полезный для совместимости со старыми системами.
Заключение
Создание файлов Excel на JavaScript не требует серверной части или Microsoft Excel. С помощью Spire.XLS for JavaScript вы можете создавать книги с нуля, записывать типизированные данные, добавлять формулы, применять форматирование и организовывать данные на нескольких листах — всё в браузере.
Начните с базового примера выше, затем добавляйте формулы и форматирование по мере необходимости. Для интеграции с React и экспорта HTML-таблиц см. наш специальный учебник по экспорту.