Skip to content

Latest commit

 

History

History
2997 lines (2315 loc) · 173 KB

README_zh.md

File metadata and controls

2997 lines (2315 loc) · 173 KB

@zurmokeeper/exceljs

Build status Code Quality: Javascript Total Alerts

读取,操作并写入电子表格数据和样式到 XLSX 和 JSON 文件。

一个 Excel 电子表格文件逆向工程项目。

特别鸣谢

此项目代码基于 exceljs 2023-5-5 的最后一次提交, [commitid](https://github.com/exceljs/exceljs/commit/ ec92cb3b898bdf7f806ff9d7b8370c955ee8ba20), exceljs的最新版本是V4.3.0,感谢exceljs项目所有的开发者

@zurmokeeper/exceljs 兼容 exceljs V4.3.0和之前的版本,可以放心切换使用。

安装

npm install @zurmokeeper/exceljs

新的功能!

自V4.4.3以后,新版本详细更新内容在这里.

V4.4.3 新的功能!

变更日志:

V4.4.2 新的功能!

变更日志:

PS: 自 V4.4.2 @zurmokeeper/exceljs 新增单元格插入内部链接支持 Sheet2!A1:B1 和 A1:B1等形式,原来只支持 Sheet2!A1,使用方式如下:

const wb = new ExcelJS.Workbook();
const ws1 = wb.addWorksheet('Sheet1');
const ws2 = wb.addWorksheet('Sheet2');

'#'是必须的,@zurmokeeper/exceljs 是通过'#'来区分内部链接的,默认会被认为是非内部链接,旧版本使用也要手动加上 '#' ,如何没加的话
// internal hyperlink
ws1.getCell('A1').value = { text: 'Sheet2', hyperlink: '#Sheet2!A1' };

// internal hyperlink
ws1.getCell('A1').value = { text: 'Sheet2', hyperlink: '#Sheet2!A1:B1' };

// internal hyperlink
ws1.getCell('A1').value = { text: 'Sheet2', hyperlink: '#A1:B1' };

V4.4.1 新的功能!

变更日志:

  • 新增嵌套列功能(多表头). 感谢 jeka1985, Merged PR1889.
    Code snippets: 
    
    // new api: worksheet.makeColumns(headers)
    
  • 新增导出加密Excel文件功能.
    Code snippets: 
    
    await workbook.xlsx.writeFile(filename, {password: '123456'});
    

V4.4.0 新的功能!

变更日志:

  • 新增读取加密Excel的功能 (支持前端和后端(Node.js))
    Code snippets:
    
    // read from a stream, decrypt excel files encrypted with password
    // const workbook = new Excel.Workbook();
    // await workbook.xlsx.readFile(filename, {password:'123456'});
    

新的功能!

贡献

欢迎贡献!这可以帮助我了解大家需要一些什么功能,或者哪些 bugs 造成了极大的麻烦。

我只有一个请求;如果您提交对错误修复的请求(PR),请添加一个能够解决问题的单元测试或集成测试(在 spec 文件夹中)。 即使只是测试失败的请求(PR)也可以 - 我可以分析测试的过程并以此修复代码。

注意:请尽可能避免在请求(PR)中修改软件包版本。 版本一般在发布时会进行更新,任何版本更改很可能导致合并冲突。

明确地说,添加到该库的所有贡献都将包含在该库的 MIT 许可证中。

目录

导入

const ExcelJS = require('@zurmokeeper/exceljs');

ES5 导入

要使用 ES5 编译代码,请使用 dist/es5 路径。

const ExcelJS = require('exceljs/dist/es5');

**注意:**ES5 版本对许多 polyfill 都具有隐式依赖,而 exceljs 不再明确添加。 您需要在依赖项中添加 core-jsregenerator-runtime,并在导入 exceljs 之前在代码中包含以下引用:

// exceljs 所需的 polyfills
require('core-js/modules/es.promise');
require('core-js/modules/es.string.includes');
require('core-js/modules/es.object.assign');
require('core-js/modules/es.object.keys');
require('core-js/modules/es.symbol');
require('core-js/modules/es.symbol.async-iterator');
require('regenerator-runtime/runtime');

const ExcelJS = require('exceljs/dist/es5');

对于 IE 11,您还需要一个 polyfill 以支持 unicode regex 模式。 例如,

const rewritePattern = require('regexpu-core');
const {generateRegexpuOptions} = require('@babel/helper-create-regexp-features-plugin/lib/util');

const {RegExp} = global;
try {
  new RegExp('a', 'u');
} catch (err) {
  global.RegExp = function(pattern, flags) {
    if (flags && flags.includes('u')) {
      return new RegExp(rewritePattern(pattern, flags, generateRegexpuOptions({flags, pattern})));
    }
    return new RegExp(pattern, flags);
  };
  global.RegExp.prototype = RegExp.prototype;
}

浏览器端

ExcelJS 在 dist/ 文件夹内发布了两个支持浏览器的包:

一个是隐式依赖 core-js polyfills 的...

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.js"></script>
<script src="exceljs.js"></script>

另一个则没有...

<script src="--your-project's-pollyfills-here--"></script>
<script src="exceljs.bare.js"></script>

接口

创建工作簿

const workbook = new ExcelJS.Workbook();

设置工作簿属性

workbook.creator = 'Me';
workbook.lastModifiedBy = 'Her';
workbook.created = new Date(1985, 8, 30);
workbook.modified = new Date();
workbook.lastPrinted = new Date(2016, 9, 27);
// 将工作簿日期设置为 1904 年日期系统
workbook.properties.date1904 = true;

设置计算属性

// 在加载时强制工作簿计算属性
workbook.calcProperties.fullCalcOnLoad = true;

工作簿视图

工作簿视图控制在查看工作簿时 Excel 将打开多少个单独的窗口。

workbook.views = [
  {
    x: 0, y: 0, width: 10000, height: 20000,
    firstSheet: 0, activeTab: 1, visibility: 'visible'
  }
]

添加工作表

const sheet = workbook.addWorksheet('My Sheet');

使用 addWorksheet 函数的第二个参数来指定工作表的选项。

示例:

// 创建带有红色标签颜色的工作表
const sheet = workbook.addWorksheet('My Sheet', {properties:{tabColor:{argb:'FFC0000'}}});

// 创建一个隐藏了网格线的工作表
const sheet = workbook.addWorksheet('My Sheet', {views: [{showGridLines: false}]});

// 创建一个第一行和列冻结的工作表
const sheet = workbook.addWorksheet('My Sheet', {views:[{xSplit: 1, ySplit:1}]});

// 使用A4设置的页面设置设置创建新工作表 - 横向
const worksheet =  workbook.addWorksheet('My Sheet', {
  pageSetup:{paperSize: 9, orientation:'landscape'}
});

// 创建一个具有页眉页脚的工作表
const sheet = workbook.addWorksheet('My Sheet', {
  headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"}
});

// 创建一个冻结了第一行和第一列的工作表
const sheet = workbook.addWorksheet('My Sheet', {views:[{state: 'frozen', xSplit: 1, ySplit:1}]});

删除工作表

使用工作表的 id 从工作簿中删除工作表。

示例:

// 创建工作表
const sheet = workbook.addWorksheet('My Sheet');

// 使用工作表 id 删除工作表
workbook.removeWorksheet(sheet.id)

访问工作表

// 遍历所有工作表
// 注意: workbook.worksheets.forEach 仍然是可以正常运行的, 但是以下的方式更好
workbook.eachSheet(function(worksheet, sheetId) {
  // ...
});

// 按 name 提取工作表
const worksheet = workbook.getWorksheet('My Sheet');

// 按 id 提取工作表
const worksheet = workbook.getWorksheet(1);

工作表状态

// 使工作表可见
worksheet.state = 'visible';

// 隐藏工作表
worksheet.state = 'hidden';

// 从“隐藏/取消隐藏”对话框中隐藏工作表
worksheet.state = 'veryHidden';

工作表属性

工作表支持属性存储,以允许控制工作表的某些功能。

// 创建具有属性的新工作表
const worksheet = workbook.addWorksheet('sheet', {properties:{tabColor:{argb:'FF00FF00'}}});

// 创建一个具有属性的可写的新工作表
const worksheetWriter = workbookWriter.addWorksheet('sheet', {properties:{outlineLevelCol:1}});

// 之后调整属性(工作表读写器不支持该操作)
worksheet.properties.outlineLevelCol = 2;
worksheet.properties.defaultRowHeight = 15;

支持的属性

属性名 默认值 描述
tabColor undefined 标签的颜色
outlineLevelCol 0 工作表列大纲级别
outlineLevelRow 0 工作表行大纲级别
defaultRowHeight 15 默认行高
defaultColWidth (optional) 默认列宽
dyDescent 55 TBD

工作表尺寸

一些新的尺寸属性已添加到工作表中...

属性名 描述
rowCount 文档的总行数。 等于具有值的最后一行的行号。
actualRowCount 具有值的行数的计数。 如果中间文档行为空,则该行将不包括在计数中。
columnCount 文档的总列数。 等于所有行的最大单元数。
actualColumnCount 具有值的列数的计数。

页面设置

所有可能影响工作表打印的属性都保存在工作表上的 pageSetup 对象中。

// 使用 A4 横向的页面设置创建新工作表
const worksheet =  workbook.addWorksheet('sheet', {
  pageSetup:{paperSize: 9, orientation:'landscape'}
});

// 使用适合页面的pageSetup设置创建一个新的工作表编写器
const worksheetWriter = workbookWriter.addWorksheet('sheet', {
  pageSetup:{fitToPage: true, fitToHeight: 5, fitToWidth: 7}
});

// 之后调整页面设置配置
worksheet.pageSetup.margins = {
  left: 0.7, right: 0.7,
  top: 0.75, bottom: 0.75,
  header: 0.3, footer: 0.3
};

// 设置工作表的打印区域
worksheet.pageSetup.printArea = 'A1:G20';

// 通过使用 `&&` 分隔打印区域来设置多个打印区域
worksheet.pageSetup.printArea = 'A1:G10&&A11:G20';

// 在每个打印页面上重复特定的行
worksheet.pageSetup.printTitlesRow = '1:3';

// 在每个打印页面上重复特定列
worksheet.pageSetup.printTitlesColumn = 'A:C';

支持的页面设置配置项

属性名 默认值 描述
margins 页面上的空白边距。 单位为英寸。
orientation 'portrait' 页面方向 - 即较高 ('portrait') 或者较宽 ('landscape')
horizontalDpi 4294967295 水平方向上的 DPI。默认值为 -1
verticalDpi 4294967295 垂直方向上的 DPI。默认值为 -1
fitToPage 是否使用 fitToWidthfitToHeightscale 设置。默认基于存在于 pageSetup 对象中的设置-如果两者都存在,则 scale 优先级高(默认值为 false)。
pageOrder 'downThenOver' 打印页面的顺序-['downThenOver', 'overThenDown'] 之一
blackAndWhite false 无色打印
draft false 打印质量较低(墨水)
cellComments 'None' 在何处放置批注-['atEnd','asDisplayed','None']中的一个
errors 'displayed' 哪里显示错误 -['dash', 'blank', 'NA', 'displayed'] 之一
scale 100 增加或减小打印尺寸的百分比值。 当 fitToPagefalse 时激活
fitToWidth 1 纸张应打印多少页宽。 当 fitToPagetrue 时激活
fitToHeight 1 纸张应打印多少页高。 当 fitToPagetrue 时激活
paperSize 使用哪种纸张尺寸(见下文)
showRowColHeaders false 是否显示行号和列字母
showGridLines false 是否显示网格线
firstPageNumber 第一页使用哪个页码
horizontalCentered false 是否将工作表数据水平居中
verticalCentered false 是否将工作表数据垂直居中

示例纸张尺寸

属性名
Letter undefined
Legal 5
Executive 7
A3 8
A4 9
A5 11
B5 (JIS) 13
Envelope #10 20
Envelope DL 27
Envelope C5 28
Envelope B5 34
Envelope Monarch 37
Double Japan Postcard Rotated 82
16K 197x273 mm 119

页眉和页脚

这是添加页眉和页脚的方法。 添加的内容主要是文本,例如时间,简介,文件信息等,您可以设置文本的样式。 此外,您可以为首页和偶数页设置不同的文本。

注意:目前不支持图片。

// 创建一个带有页眉和页脚的工作表
var sheet = workbook.addWorksheet('My Sheet', {
  headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"}
});

// 创建一个带有页眉和页脚可写的工作表
var worksheetWriter = workbookWriter.addWorksheet('sheet', {
  headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"}
});
// 代码中出现的&开头字符对应变量,相关信息可查阅下文的变量表
// 设置页脚(默认居中),结果:“第 2 页,共 16 页”
worksheet.headerFooter.oddFooter = "第 &P 页,共 &N 页";

// 将页脚(默认居中)设置为粗体,结果是:“第2页,共16页”
worksheet.headerFooter.oddFooter = "Page &P of &N";

// 将左页脚设置为 18px 并以斜体显示。 结果:“第2页,共16页”
worksheet.headerFooter.oddFooter = "&LPage &P of &N";

// 将中间标题设置为灰色Aril,结果为:“ 52 exceljs”
worksheet.headerFooter.oddHeader = "&C&KCCCCCC&\"Aril\"52 exceljs";

// 设置页脚的左,中和右文本。 结果:页脚左侧为“ Exceljs”。 页脚中心的“ demo.xlsx”。 页脚右侧的“第2页”
worksheet.headerFooter.oddFooter = "&Lexceljs&C&F&RPage &P";

// 在首页添加不同的页眉和页脚
worksheet.headerFooter.differentFirst = true;
worksheet.headerFooter.firstHeader = "Hello Exceljs";
worksheet.headerFooter.firstFooter = "Hello World"

支持的 headerFooter 设置

属性名 默认值 描述
differentFirst false differentFirst 的值设置为 true,这表示第一页的页眉/页脚与其他页不同
differentOddEven false differentOddEven 的值设置为 true,表示奇数页和偶数页的页眉/页脚不同
oddHeader null 设置奇数(默认)页面的标题字符串,可以设置格式化字符串
oddFooter null 设置奇数(默认)页面的页脚字符串,可以设置格式化字符串
evenHeader null 设置偶数页的标题字符串,可以设置格式化字符串
evenFooter null 为偶数页设置页脚字符串,可以设置格式化字符串
firstHeader null 设置首页的标题字符串,可以设置格式化字符串
firstFooter null 设置首页的页脚字符串,可以设置格式化字符串

脚本命令

命令 描述
&L 将位置设定在左侧
&C 将位置设置在中心
&R 将位置设定在右边
&P 当前页码
&N 总页数
&D 当前日期
&T 当前时间
&G 照片
&A 工作表名称
&F 文件名称
&B 加粗文本
&I 斜体文本
&U 文本下划线
&"font name" 字体名称,例如&“ Aril”
&font size 字体大小,例如12
&KHEXCode 字体颜色,例如 &KCCCCCC

工作表视图

现在,工作表支持视图列表,这些视图控制Excel如何显示工作表:

  • frozen - 顶部和左侧的许多行和列被冻结在适当的位置。 仅右下部分会滚动
  • split - 该视图分为4个部分,每个部分可半独立滚动。

每个视图还支持各种属性:

属性名 默认值 描述
state 'normal' 控制视图状态 - 'normal', 'frozen' 或者 'split' 之一
rightToLeft false 将工作表视图的方向设置为从右到左
activeCell undefined 当前选择的单元格
showRuler true 在页面布局中显示或隐藏标尺
showRowColHeaders true 显示或隐藏行标题和列标题(例如,顶部的 A1,B1 和左侧的1,2,3)
showGridLines true 显示或隐藏网格线(针对未定义边框的单元格显示)
zoomScale 100 用于视图的缩放比例
zoomScaleNormal 100 正常缩放视图
style undefined 演示样式- pageBreakPreviewpageLayout 之一。 注意:页面布局与 frozen 视图不兼容

冻结视图

冻结视图支持以下额外属性:

属性名 默认值 描述
xSplit 0 冻结多少列。要仅冻结行,请将其设置为 0undefined
ySplit 0 冻结多少行。要仅冻结列,请将其设置为 0undefined
topLeftCell special 哪个单元格将在右下窗格中的左上角。注意:不能是冻结单元格。默认为第一个未冻结的单元格
worksheet.views = [
  {state: 'frozen', xSplit: 2, ySplit: 3, topLeftCell: 'G10', activeCell: 'A1'}
];

拆分视图

拆分视图支持以下额外属性:

属性名 默认值 描述
xSplit 0 从左侧多少个点起,以放置拆分器。要垂直拆分,请将其设置为 0undefined
ySplit 0 从顶部多少个点起,放置拆分器。要水平拆分,请将其设置为 0undefined
topLeftCell undefined 哪个单元格将在右下窗格中的左上角。
activePane undefined 哪个窗格将处于活动状态-topLefttopRightbottomLeftbottomRight 中的一个
worksheet.views = [
  {state: 'split', xSplit: 2000, ySplit: 3000, topLeftCell: 'G10', activeCell: 'A1'}
];

自动筛选器

可以对工作表应用自动筛选器。

worksheet.autoFilter = 'A1:C1';

尽管范围字符串是 autoFilter 的标准形式,但工作表还将支持以下值:

// 将自动筛选器设置为从 A1 到 C1
worksheet.autoFilter = {
  from: 'A1',
  to: 'C1',
}

// 将自动筛选器设置为从第3行第1列的单元格到第5行第12列的单元格
worksheet.autoFilter = {
  from: {
    row: 3,
    column: 1
  },
  to: {
    row: 5,
    column: 12
  }
}

// 将自动筛选器设置为从D3到第7行第5列中的单元格
worksheet.autoFilter = {
  from: 'D3',
  to: {
    row: 7,
    column: 5
  }
}

// 添加列标题并定义列键和宽度
// 注意:这些列结构仅是构建工作簿的方便之处,除了列宽之外,它们不会完全保留。
worksheet.columns = [
  { header: 'Id', key: 'id', width: 10 },
  { header: 'Name', key: 'name', width: 32 },
  { header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1 }
];

// 通过键,字母和基于1的列号访问单个列
const idCol = worksheet.getColumn('id');
const nameCol = worksheet.getColumn('B');
const dobCol = worksheet.getColumn(3);

// 设置列属性

// 注意:将覆盖 C1 单元格值
dobCol.header = 'Date of Birth';

// 注意:这将覆盖 C1:C2 单元格值
dobCol.header = ['Date of Birth', 'A.K.A. D.O.B.'];

// 从现在开始,此列将以 “dob” 而不是 “DOB” 建立索引
dobCol.key = 'dob';

dobCol.width = 15;

// 如果需要,隐藏列
dobCol.hidden = true;

// 为列设置大纲级别
worksheet.getColumn(4).outlineLevel = 0;
worksheet.getColumn(5).outlineLevel = 1;

// 列支持一个只读字段,以指示基于 `OutlineLevel` 的折叠状态
expect(worksheet.getColumn(4).collapsed).to.equal(false);
expect(worksheet.getColumn(5).collapsed).to.equal(true);

// 在该列右边插入一个分页符
dobCol.addPageBreak();

// 遍历此列中的所有当前单元格
dobCol.eachCell(function(cell, rowNumber) {
  // ...
});

// 遍历此列中的所有当前单元格,包括空单元格
dobCol.eachCell({ includeEmpty: true }, function(cell, rowNumber) {
  // ...
});

// 添加一列新值
worksheet.getColumn(6).values = [1,2,3,4,5];

// 添加稀疏列值
worksheet.getColumn(7).values = [,,2,3,,5,,7,,,,11];

// 剪切一列或多列(右边的列向左移动)
// 如果定义了列属性,则会相应地对其进行切割或移动
// 已知问题:如果拼接导致任何合并的单元格移动,结果可能是不可预测的
worksheet.spliceColumns(3,2);

// 删除一列,再插入两列。
// 注意:第4列及以上的列将右移1列。
// 另外:如果工作表中的行数多于列插入项中的值,则行将仍然被插入,就好像值存在一样。
const newCol3Values = [1,2,3,4,5];
const newCol4Values = ['one', 'two', 'three', 'four', 'five'];
worksheet.spliceColumns(3, 1, newCol3Values, newCol4Values);

// 嵌套列
// 使用这个API来构建嵌套列(实现多级表头)
worksheet.makeColumns([
  {
    id: 1, 
    title: 'Some', 
  },
  {id: 2, title: 'Qwe'},
  {id: 3, title: 'Foo'},
  {
    id: 4,
    title: 'Zoo',
    children: [
      { id: 41, title: 'Zoo 1' },
      { id: 42, title: 'Zoo 2' },
      { id: 44, title: 'Zoo 3' },
      { id: 45, title: 'Zoo 4' },
    ]
  }
]);

// 获取一个行对象。如果尚不存在,则将返回一个新的空对象
const row = worksheet.getRow(5);

// Get multiple row objects. If it doesn't already exist, new empty ones will be returned
const rows = worksheet.getRows(5, 2); // start, length (>0, else undefined is returned)

// 获取工作表中的最后一个可编辑行(如果没有,则为 `undefined`)
const row = worksheet.lastRow;

// 设置特定的行高
row.height = 42.5;

// 隐藏行
row.hidden = true;

// 为行设置大纲级别
worksheet.getRow(4).outlineLevel = 0;
worksheet.getRow(5).outlineLevel = 1;

// 行支持一个只读字段,以指示基于 `OutlineLevel` 的折叠状态
expect(worksheet.getRow(4).collapsed).to.equal(false);
expect(worksheet.getRow(5).collapsed).to.equal(true);


row.getCell(1).value = 5; // A5 的值设置为5
row.getCell('name').value = 'Zeb'; // B5 的值设置为 “Zeb” - 假设第2列仍按名称键入
row.getCell('C').value = new Date(); // C5 的值设置为当前时间

// 获取行并作为稀疏数组返回
// 注意:接口更改:worksheet.getRow(4) ==> worksheet.getRow(4).values
row = worksheet.getRow(4).values;
expect(row[5]).toEqual('Kyle');

// 通过连续数组分配行值(其中数组元素 0 具有值)
row.values = [1,2,3];
expect(row.getCell(1).value).toEqual(1);
expect(row.getCell(2).value).toEqual(2);
expect(row.getCell(3).value).toEqual(3);

// 通过稀疏数组分配行值(其中数组元素 0 为 `undefined`)
const values = []
values[5] = 7;
values[10] = 'Hello, World!';
row.values = values;
expect(row.getCell(1).value).toBeNull();
expect(row.getCell(5).value).toEqual(7);
expect(row.getCell(10).value).toEqual('Hello, World!');

// 使用列键按对象分配行值
row.values = {
  id: 13,
  name: 'Thing 1',
  dob: new Date()
};

// 在该行下方插入一个分页符
row.addPageBreak();

// 遍历工作表中具有值的所有行
worksheet.eachRow(function(row, rowNumber) {
  console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values));
});

// 遍历工作表中的所有行(包括空行)
worksheet.eachRow({ includeEmpty: true }, function(row, rowNumber) {
  console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values));
});

// 连续遍历所有非空单元格
row.eachCell(function(cell, colNumber) {
  console.log('Cell ' + colNumber + ' = ' + cell.value);
});

// 遍历一行中的所有单元格(包括空单元格)
row.eachCell({ includeEmpty: true }, function(cell, colNumber) {
  console.log('Cell ' + colNumber + ' = ' + cell.value);
});

// 提交给流一个完成的行
row.commit();

// 行尺寸
const rowSize = row.cellCount;
const numValues = row.actualCellCount;

Add Rows

// Add a couple of Rows by key-value, after the last current row, using the column keys
worksheet.addRow({id: 1, name: 'John Doe', dob: new Date(1970,1,1)});
worksheet.addRow({id: 2, name: 'Jane Doe', dob: new Date(1965,1,7)});

// Add a row by contiguous Array (assign to columns A, B & C)
worksheet.addRow([3, 'Sam', new Date()]);

// Add a row by sparse Array (assign to columns A, E & I)
const rowValues = [];
rowValues[1] = 4;
rowValues[5] = 'Kyle';
rowValues[9] = new Date();
worksheet.addRow(rowValues);

// Add a row with inherited style
// This new row will have same style as last row
// And return as row object
const newRow = worksheet.addRow(rowValues, 'i');

// Add an array of rows
const rows = [
  [5,'Bob',new Date()], // row by array
  {id:6, name: 'Barbara', dob: new Date()}
];
// add new rows and return them as array of row objects
const newRows = worksheet.addRows(rows);

// Add an array of rows with inherited style
// These new rows will have same styles as last row
// and return them as array of row objects
const newRowsStyled = worksheet.addRows(rows, 'i');
Parameter Description Default Value
value/s The new row/s values
style 'i' for inherit from row above, 'i+' to include empty cells, 'n' for none 'n'

处理单个单元格

const cell = worksheet.getCell('C3');

// 修改/添加单个单元格
cell.value = new Date(1968, 5, 1);

// 查询单元格的类型
expect(cell.type).toEqual(Excel.ValueType.Date);

// 使用单元格的字符串值
myInput.value = cell.text;

// 使用 html 安全的字符串进行渲染...
const html = '<div>' + cell.html + '</div>';

合并单元格

// 合并一系列单元格
worksheet.mergeCells('A4:B5');

// ...合并的单元格被链接起来了
worksheet.getCell('B5').value = 'Hello, World!';
expect(worksheet.getCell('B5').value).toBe(worksheet.getCell('A4').value);
expect(worksheet.getCell('B5').master).toBe(worksheet.getCell('A4'));

// ...合并的单元格共享相同的样式对象
expect(worksheet.getCell('B5').style).toBe(worksheet.getCell('A4').style);
worksheet.getCell('B5').style.font = myFonts.arial;
expect(worksheet.getCell('A4').style.font).toBe(myFonts.arial);

// 取消单元格合并将打破链接的样式
worksheet.unMergeCells('A4');
expect(worksheet.getCell('B5').style).not.toBe(worksheet.getCell('A4').style);
expect(worksheet.getCell('B5').style.font).not.toBe(myFonts.arial);

// 按左上,右下合并
worksheet.mergeCells('K10', 'M12');

// 按开始行,开始列,结束行,结束列合并(相当于 K10:M12)
worksheet.mergeCells(10,11,12,13);

Insert Rows

insertRow(pos, value, style = 'n')
insertRows(pos, values, style = 'n')

// Insert a couple of Rows by key-value, shifting down rows every time
worksheet.insertRow(1, {id: 1, name: 'John Doe', dob: new Date(1970,1,1)});
worksheet.insertRow(1, {id: 2, name: 'Jane Doe', dob: new Date(1965,1,7)});

// Insert a row by contiguous Array (assign to columns A, B & C)
worksheet.insertRow(1, [3, 'Sam', new Date()]);

// Insert a row by sparse Array (assign to columns A, E & I)
var rowValues = [];
rowValues[1] = 4;
rowValues[5] = 'Kyle';
rowValues[9] = new Date();
// insert new row and return as row object
const insertedRow = worksheet.insertRow(1, rowValues);

// Insert a row, with inherited style
// This new row will have same style as row on top of it
// And return as row object
const insertedRowInherited = worksheet.insertRow(1, rowValues, 'i');

// Insert a row, keeping original style
// This new row will have same style as it was previously
// And return as row object
const insertedRowOriginal = worksheet.insertRow(1, rowValues, 'o');

// Insert an array of rows, in position 1, shifting down current position 1 and later rows by 2 rows
var rows = [
  [5,'Bob',new Date()], // row by array
  {id:6, name: 'Barbara', dob: new Date()}
];
// insert new rows and return them as array of row objects
const insertedRows = worksheet.insertRows(1, rows);

// Insert an array of rows, with inherited style
// These new rows will have same style as row on top of it
// And return them as array of row objects
const insertedRowsInherited = worksheet.insertRows(1, rows, 'i');

// Insert an array of rows, keeping original style
// These new rows will have same style as it was previously in 'pos' position
const insertedRowsOriginal = worksheet.insertRows(1, rows, 'o');
Parameter Description Default Value
pos Row number where you want to insert, pushing down all rows from there
value/s The new row/s values
style 'i' for inherit from row above, , 'i+' to include empty cells, 'o' for original style, 'o+' to include empty cells, 'n' for none 'n'

Splice

// Cut one or more rows (rows below are shifted up)
// Known Issue: If a splice causes any merged cells to move, the results may be unpredictable
worksheet.spliceRows(4, 3);

// remove one row and insert two more.
// Note: rows 4 and below will be shifted down by 1 row.
const newRow3Values = [1, 2, 3, 4, 5];
const newRow4Values = ['one', 'two', 'three', 'four', 'five'];
worksheet.spliceRows(3, 1, newRow3Values, newRow4Values);

// Cut one or more cells (cells to the right are shifted left)
// Note: this operation will not affect other rows
row.splice(3, 2);

// remove one cell and insert two more (cells to the right of the cut cell will be shifted right)
row.splice(4, 1, 'new value 1', 'new value 2');
Parameter Description Default Value
start Starting point to splice from
count Number of rows/cells to remove
...inserts New row/cell values to insert

重复行

duplicateRow(start, amount = 1, insert = true)

const wb = new ExcelJS.Workbook();
const ws = wb.addWorksheet('duplicateTest');
ws.getCell('A1').value = 'One';
ws.getCell('A2').value = 'Two';
ws.getCell('A3').value = 'Three';
ws.getCell('A4').value = 'Four';

// 该行将重复复制第一行两次,但将替换第二行和第三行
// 如果第三个参数为 true,则它将插入2个新行,其中包含行 “One” 的值和样式
ws.duplicateRow(1,2,false);
参数 描述 默认值
start 要复制的行号(Excel中的第一个是1)
amount 您要复制行的次数 1
insert 如果要为重复项插入新行,则为 true,否则为 false 将替换已有行 true

定义名称

单个单元格(或多个单元格组)可以为它们分配名称。名称可用于公式和数据验证(可能还有更多)。

// 为单元格分配(或获取)名称(将覆盖该单元具有的其他任何名称)
worksheet.getCell('A1').name = 'PI';
expect(worksheet.getCell('A1').name).to.equal('PI');

// 为单元格分配(或获取)一组名称(单元可以具有多个名称)
worksheet.getCell('A1').names = ['thing1', 'thing2'];
expect(worksheet.getCell('A1').names).to.have.members(['thing1', 'thing2']);

// 从单元格中删除名称
worksheet.getCell('A1').removeName('thing1');
expect(worksheet.getCell('A1').names).to.have.members(['thing2']);

数据验证

单元格可以定义哪些值有效或无效,并提示用户以帮助指导它们。

验证类型可以是以下之一:

类型 描述
list 定义一组离散的有效值。Excel 将在下拉菜单中提供这些内容,以便于输入
whole 该值必须是整数
decimal 该值必须是十进制数
textLength 该值可以是文本,但长度是受控的
custom 自定义公式控制有效值

对于 listcustom 以外的其他类型,以下运算符会影响验证:

运算符 描述
between 值必须介于公式结果之间
notBetween 值不能介于公式结果之间
equal 值必须等于公式结果
notEqual 值不能等于公式结果
greaterThan 值必须大于公式结果
lessThan 值必须小于公式结果
greaterThanOrEqual 值必须大于或等于公式结果
lessThanOrEqual 值必须小于或等于公式结果
// 指定有效值的列表(One,Two,Three,Four)。
// Excel 将提供一个包含这些值的下拉列表。
worksheet.getCell('A1').dataValidation = {
  type: 'list',
  allowBlank: true,
  formulae: ['"One,Two,Three,Four"']
};

// 指定范围内的有效值列表。
// Excel 将提供一个包含这些值的下拉列表。
worksheet.getCell('A1').dataValidation = {
  type: 'list',
  allowBlank: true,
  formulae: ['$D$5:$F$5']
};

// 指定单元格必须为非5的整数。
// 向用户显示适当的错误消息(如果他们弄错了)
worksheet.getCell('A1').dataValidation = {
  type: 'whole',
  operator: 'notEqual',
  showErrorMessage: true,
  formulae: [5],
  errorStyle: 'error',
  errorTitle: 'Five',
  error: 'The value must not be Five'
};

// 指定单元格必须为1.5到7之间的十进制数字。
// 添加“工具提示”以帮助指导用户
worksheet.getCell('A1').dataValidation = {
  type: 'decimal',
  operator: 'between',
  allowBlank: true,
  showInputMessage: true,
  formulae: [1.5, 7],
  promptTitle: 'Decimal',
  prompt: 'The value must between 1.5 and 7'
};

// 指定单元格的文本长度必须小于15
worksheet.getCell('A1').dataValidation = {
  type: 'textLength',
  operator: 'lessThan',
  showErrorMessage: true,
  allowBlank: true,
  formulae: [15]
};

// 指定单元格必须是2016年1月1日之前的日期
worksheet.getCell('A1').dataValidation = {
  type: 'date',
  operator: 'lessThan',
  showErrorMessage: true,
  allowBlank: true,
  formulae: [new Date(2016,0,1)]
};

单元格注释

将旧样式的注释添加到单元格

// 纯文字笔记
worksheet.getCell('A1').note = 'Hello, ExcelJS!';

// 彩色格式化的笔记
ws.getCell('B1').note = {
  texts: [
    {'font': {'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'This is '},
    {'font': {'italic': true, 'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'a'},
    {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' '},
    {'font': {'size': 12, 'color': {'argb': 'FFFF6600'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'colorful'},
    {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' text '},
    {'font': {'size': 12, 'color': {'argb': 'FFCCFFCC'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'with'},
    {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' in-cell '},
    {'font': {'bold': true, 'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'format'},
  ],
  margins: {
    insetmode: 'custom',
    inset: [0.25, 0.25, 0.35, 0.35]
  },
  protection: {
    locked: True,
    lockText: False
  },
  editAs: 'twoCells'
};

// 移除单元格注释
ws.getCell('B1').removeNote()

单元格批注属性

下表定义了单元格注释已支持的属性。

Field Required Default Value Description
texts Y 评论文字
margins N {} 确定自动或自定义设置单元格注释的边距值
protection N {} 可以使用保护属性来指定对象和对象文本的锁定状态
editAs N 'absolute' 可以使用'editAs'属性来指定注释如何锚定到单元格

单元格批注页边距

确定单元格批注的页面距设置模式,自动或者自定义模式。

ws.getCell('B1').note.margins = {
  insetmode: 'custom',
  inset: [0.25, 0.25, 0.35, 0.35]
}

已支持的页边距属性

Property Required Default Value Description
insetmode N 'auto' 确定是否自动设置注释边距,并且值是'auto' 或者 'custom'
inset N [0.13, 0.13, 0.25, 0.25] 批注页边距的值,单位是厘米, 方向是左-上-右-下

注意:只有当 insetmode的值设置为'custom'时,inset的设置才生效。

单元格批注保护

可以使用保护属性来修改单元级别保护。

ws.getCell('B1').note.protection = {
  locked: 'False',
  lockText: 'False',
};

已支持的保护属性

Property Required Default Value Description
locked N 'True' 此元素指定在保护工作表时对象已锁定
lockText N 'True' 该元素指定对象的文本已锁定

单元格批注对象位置属性

单元格注释还可以具有属性 'editAs',该属性将控制注释如何锚定到单元格。 它可以具有以下值之一:

ws.getCell('B1').note.editAs = 'twoCells'
Value Description
twoCells 它指定注释的大小、位置随单元格而变
oneCells 它指定注释的大小固定,位置随单元格而变
absolute 这是默认值,它指定注释的大小、位置均固定

表格

表允许表格内数据的表内操作。

要将表添加到工作表,请定义表模型并调用 addTable

// 将表格添加到工作表
ws.addTable({
  name: 'MyTable',
  ref: 'A1',
  headerRow: true,
  totalsRow: true,
  style: {
    theme: 'TableStyleDark3',
    showRowStripes: true,
  },
  columns: [
    {name: 'Date', totalsRowLabel: 'Totals:', filterButton: true},
    {name: 'Amount', totalsRowFunction: 'sum', filterButton: false},
  ],
  rows: [
    [new Date('2019-07-20'), 70.10],
    [new Date('2019-07-21'), 70.60],
    [new Date('2019-07-22'), 70.10],
  ],
});

注意:将表格添加到工作表将通过放置表格的标题和行数据来修改工作表。 结果就是表格覆盖的工作表上的所有数据(包括标题和所有的)都将被覆盖。

表格属性

下表定义了表格支持的属性。

表属性 描述 是否需要 默认值
name 表格名称 Y
displayName 表格的显示名称 N name
ref 表格的左上方单元格 Y
headerRow 在表格顶部显示标题 N true
totalsRow 在表格底部显示总计 N false
style 额外的样式属性 N {}
columns 列定义 Y
rows 数据行 Y

表格样式属性

下表定义了表格中支持的属性样式属性。

样式属性 描述 是否需要 默认值
theme 桌子的颜色主题 N 'TableStyleMedium2'
showFirstColumn 突出显示第一列(粗体) N false
showLastColumn 突出显示最后一列(粗体) N false
showRowStripes 用交替的背景色显示行 N false
showColumnStripes 用交替的背景色显示列 N false

表格列属性

下表定义了每个表格列中支持的属性。

列属性 描述 是否需要 默认值
name 列名,也用在标题中 Y
filterButton 切换标题中的过滤器控件 N false
totalsRowLabel 用于描述统计行的标签(第一列) N 'Total'
totalsRowFunction 统计函数名称 N 'none'
totalsRowFormula 自定义函数的可选公式 N

统计函数

下表列出了由列定义的 totalsRowFunction 属性的有效值。如果使用 'custom' 以外的任何值,则无需包括关联的公式,因为该公式将被表格插入。

统计函数 描述
none 此列没有统计函数
average 计算列的平均值
countNums 统计数字条目数
count 条目数
max 此列中的最大值
min 此列中的最小值
stdDev 该列的标准偏差
var 此列的方差
sum 此列的条目总数
custom 自定义公式。 需要关联的 totalsRowFormula 值。

表格样式主题

有效的主题名称遵循以下模式:

  • "TableStyle[Shade][Number]"

Shades(阴影),Number(数字)可以是以下之一:

  • Light, 1-21
  • Medium, 1-28
  • Dark, 1-11

对于无主题,请使用值 null

注意:exceljs 尚不支持自定义表格主题。

修改表格

表格支持一组操作函数,这些操作函数允许添加或删除数据以及更改某些属性。由于这些操作中的许多操作可能会对工作表产生副作用,因此更改必须在完成后立即提交。

表中的所有索引值均基于零,因此第一行号和第一列号为 0

添加或删除标题和统计

const table = ws.getTable('MyTable');

// 打开标题行
table.headerRow = true;

// 关闭统计行
table.totalsRow = false;

// 将表更改提交到工作表中
table.commit();

重定位表

const table = ws.getTable('MyTable');

// 表格左上移至 D4
table.ref = 'D4';

// 将表更改提交到工作表中
table.commit();

添加和删除行

const table = ws.getTable('MyTable');

// 删除前两行
table.removeRows(0, 2);

// 在索引 5 处插入新行
table.addRow([new Date('2019-08-05'), 5, 'Mid'], 5);

// 在表格底部追加新行
table.addRow([new Date('2019-08-10'), 10, 'End']);

// 将表更改提交到工作表中
table.commit();

添加和删除列

const table = ws.getTable('MyTable');

// 删除第二列
table.removeColumns(1, 1);

// 在索引 1 处插入新列(包含数据)
table.addColumn(
  {name: 'Letter', totalsRowFunction: 'custom', totalsRowFormula: 'ROW()', totalsRowResult: 6, filterButton: true},
  ['a', 'b', 'c', 'd'],
  2
);

// 将表更改提交到工作表中
table.commit();

更改列属性

const table = ws.getTable('MyTable');

// 获取第二列的列包装器
const column = table.getColumn(1);

// 设置一些属性
column.name = 'Code';
column.filterButton = true;
column.style = {font:{bold: true, name: 'Comic Sans MS'}};
column.totalsRowLabel = 'Totals';
column.totalsRowFunction = 'custom';
column.totalsRowFormula = 'ROW()';
column.totalsRowResult = 10;

// 将表更改提交到工作表中
table.commit();

样式

单元格,行和列均支持一组丰富的样式和格式,这些样式和格式会影响单元格的显示方式。

通过分配以下属性来设置样式:

// 为单元格分配样式
ws.getCell('A1').numFmt = '0.00%';

// 将样式应用于工作表列
ws.columns = [
  { header: 'Id', key: 'id', width: 10 },
  { header: 'Name', key: 'name', width: 32, style: { font: { name: 'Arial Black' } } },
  { header: 'D.O.B.', key: 'DOB', width: 10, style: { numFmt: 'dd/mm/yyyy' } }
];

// 将第3列设置为“货币格式”
ws.getColumn(3).numFmt = '"£"#,##0.00;[Red]\-"£"#,##0.00';

// 将第2行设置为 Comic Sans。
ws.getRow(2).font = { name: 'Comic Sans MS', family: 4, size: 16, underline: 'double', bold: true };

将样式应用于行或列时,它将应用于该行或列中所有当前存在的单元格。另外,创建的任何新单元格都将从其所属的行和列继承其初始样式。

如果单元格的行和列都定义了特定的样式(例如,字体),则该单元格所在行样式比列样式具有更高优先级。但是,如果行和列定义了不同的样式(例如 column.numFmtrow.font),则单元格将继承行的字体和列的 numFmt

注意:以上所有属性(numFmt(字符串)除外)都是 JS 对象结构。如果将同一样式对象分配给多个电子表格实体,则每个实体将共享同一样式对象。如果样式对象后来在电子表格序列化之前被修改,则所有引用该样式对象的实体也将被修改。此行为旨在通过减少创建的JS对象的数量来优先考虑性能。如果希望样式对象是独立的,则需要先对其进行克隆,然后再分配它们。同样,默认情况下,如果电子表格实体共享相似的样式,则从文件(或流)中读取文档时,它们也将引用相同的样式对象。

数字格式

// 将值显示为“ 1 3/5”
ws.getCell('A1').value = 1.6;
ws.getCell('A1').numFmt = '# ?/?';

// 显示为“ 1.60%”
ws.getCell('B1').value = 0.016;
ws.getCell('B1').numFmt = '0.00%';

字体

// for the wannabe graphic designers out there
ws.getCell('A1').font = {
  name: 'Comic Sans MS',
  family: 4,
  size: 16,
  underline: true,
  bold: true
};

// for the graduate graphic designers...
ws.getCell('A2').font = {
  name: 'Arial Black',
  color: { argb: 'FF00FF00' },
  family: 2,
  size: 14,
  italic: true
};

// 垂直对齐
ws.getCell('A3').font = {
  vertAlign: 'superscript'
};

// 注意:该单元格将存储对分配的字体对象的引用。
// 如果之后更改了字体对象,则单元字体也将更改。
const font = { name: 'Arial', size: 12 };
ws.getCell('A3').font = font;
font.size = 20; // 单元格 A3 现在具有20号字体!

// 从文件或流中读取工作簿后,共享相似字体的单元格可能引用相同的字体对象
字体属性 描述 示例值
name 字体名称。 'Arial', 'Calibri', etc.
family 备用字体家族。整数值。 1 - Serif, 2 - Sans Serif, 3 - Mono, Others - unknown
scheme 字体方案。 'minor', 'major', 'none'
charset 字体字符集。整数值。 1, 2, etc.
size 字体大小。整数值。 9, 10, 12, 16, etc.
color 颜色描述,一个包含 ARGB 值的对象。 { argb: 'FFFF0000'}
bold 字体 粗细 true, false
italic 字体 倾斜 true, false
underline 字体 下划线 样式 true, false, 'none', 'single', 'double', 'singleAccounting', 'doubleAccounting'
strike 字体 删除线 true, false
outline 字体轮廓 true, false
vertAlign 垂直对齐 'superscript', 'subscript'

对齐

// 将单元格对齐方式设置为左上,中间居中,右下
ws.getCell('A1').alignment = { vertical: 'top', horizontal: 'left' };
ws.getCell('B1').alignment = { vertical: 'middle', horizontal: 'center' };
ws.getCell('C1').alignment = { vertical: 'bottom', horizontal: 'right' };

// 将单元格设置为自动换行
ws.getCell('D1').alignment = { wrapText: true };

// 将单元格缩进设置为1
ws.getCell('E1').alignment = { indent: 1 };

// 将单元格文本旋转设置为向上30deg,向下45deg和垂直文本
ws.getCell('F1').alignment = { textRotation: 30 };
ws.getCell('G1').alignment = { textRotation: -45 };
ws.getCell('H1').alignment = { textRotation: 'vertical' };

有效的对齐属性值

水平的 垂直 文本换行 自适应 缩进 阅读顺序 文本旋转
left top true true integer rtl 0 to 90
center middle false false ltr -1 to -90
right bottom vertical
fill distributed
justify justify
centerContinuous
distributed

边框

// 在A1周围设置单个细边框
ws.getCell('A1').border = {
  top: {style:'thin'},
  left: {style:'thin'},
  bottom: {style:'thin'},
  right: {style:'thin'}
};

// 在A3周围设置双细绿色边框
ws.getCell('A3').border = {
  top: {style:'double', color: {argb:'FF00FF00'}},
  left: {style:'double', color: {argb:'FF00FF00'}},
  bottom: {style:'double', color: {argb:'FF00FF00'}},
  right: {style:'double', color: {argb:'FF00FF00'}}
};

// 在A5中设置厚红十字边框
ws.getCell('A5').border = {
  diagonal: {up: true, down: true, style:'thick', color: {argb:'FFFF0000'}}
};

有效边框样式

  • thin
  • dotted
  • dashDot
  • hair
  • dashDotDot
  • slantDashDot
  • mediumDashed
  • mediumDashDotDot
  • mediumDashDot
  • medium
  • double
  • thick

填充

// 用红色深色垂直条纹填充A1
ws.getCell('A1').fill = {
  type: 'pattern',
  pattern:'darkVertical',
  fgColor:{argb:'FFFF0000'}
};

// 在A2中填充深黄色格子和蓝色背景
ws.getCell('A2').fill = {
  type: 'pattern',
  pattern:'darkTrellis',
  fgColor:{argb:'FFFFFF00'},
  bgColor:{argb:'FF0000FF'}
};

// 从左到右用蓝白蓝渐变填充A3
ws.getCell('A3').fill = {
  type: 'gradient',
  gradient: 'angle',
  degree: 0,
  stops: [
    {position:0, color:{argb:'FF0000FF'}},
    {position:0.5, color:{argb:'FFFFFFFF'}},
    {position:1, color:{argb:'FF0000FF'}}
  ]
};


// 从中心开始用红绿色渐变填充A4
ws.getCell('A4').fill = {
  type: 'gradient',
  gradient: 'path',
  center:{left:0.5,top:0.5},
  stops: [
    {position:0, color:{argb:'FFFF0000'}},
    {position:1, color:{argb:'FF00FF00'}}
  ]
};

填充模式

属性 是否需要 描述
type Y 值: 'pattern'
指定此填充使用模式
pattern Y 指定模式类型 (查看下面 有效模式类型 )
fgColor N 指定图案前景色。默认为黑色。
bgColor N 指定图案背景色。默认为白色。

有效模式类型

  • none
  • solid
  • darkGray
  • mediumGray
  • lightGray
  • gray125
  • gray0625
  • darkHorizontal
  • darkVertical
  • darkDown
  • darkUp
  • darkGrid
  • darkTrellis
  • lightHorizontal
  • lightVertical
  • lightDown
  • lightUp
  • lightGrid
  • lightTrellis

渐变填充

属性 是否需要 描述
type Y 值: 'gradient'
指定此填充使用渐变
gradient Y 指定渐变类型。['angle','path'] 之一
degree angle 对于“角度”渐变,指定渐变的方向。0 是从左到右。值从 1-359 顺时针旋转方向
center path 对于“路径”渐变。指定路径起点的相对坐标。“左”和“顶”值的范围是 0 到 1
stops Y 指定渐变颜色序列。是包含位置和颜色(从位置 0 开始到位置 1 结束)的对象的数组。中间位置可用于指定路径上的其他颜色。

注意事项

使用上面的接口,可能会创建使用XLSX编辑器程序无法实现的渐变填充效果。例如,Excel 仅支持0、45、90 和 135 的角度梯度。类似地,stops 的顺序也可能受到 UI 的限制,其中位置 [0,1] 或[0,0.5,1] 是唯一的选择。请谨慎处理此填充,以确保目标 XLSX 查看器支持该填充。

富文本

现在,单个单元格支持RTF文本或单元格格式化。富文本值可以控制文本值内任意数量的子字符串的字体属性。有关支持哪些字体属性的详细信息,请参见字体

ws.getCell('A1').value = {
  'richText': [
    {'font': {'size': 12,'color': {'theme': 0},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': 'This is '},
    {'font': {'italic': true,'size': 12,'color': {'theme': 0},'name': 'Calibri','scheme': 'minor'},'text': 'a'},
    {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' '},
    {'font': {'size': 12,'color': {'argb': 'FFFF6600'},'name': 'Calibri','scheme': 'minor'},'text': 'colorful'},
    {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' text '},
    {'font': {'size': 12,'color': {'argb': 'FFCCFFCC'},'name': 'Calibri','scheme': 'minor'},'text': 'with'},
    {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' in-cell '},
    {'font': {'bold': true,'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': 'format'}
  ]
};

expect(ws.getCell('A1').text).to.equal('This is a colorful text with in-cell format');
expect(ws.getCell('A1').type).to.equal(Excel.ValueType.RichText);

单元格保护

可以使用保护属性来修改单元级别保护。

ws.getCell('A1').protection = {
  locked: false,
  hidden: true,
};

支持的保护属性

属性 默认值 描述
locked true 指定在工作表受保护的情况下是否将单元格锁定。
hidden false 指定如果工作表受保护,则单元格的公式是否可见。

条件格式化

条件格式化允许工作表根据单元格值或任意公式显示特定的样式,图标等。

条件格式设置规则是在工作表级别添加的,通常会覆盖一系列单元格。

可以将多个规则应用于给定的单元格范围,并且每个规则都将应用自己的样式。

如果多个规则影响给定的单元格,则规则优先级值将确定如果竞争样式冲突,则哪个规则胜出。优先级值较低的规则获胜。如果没有为给定规则指定优先级值,ExcelJS 将按升序分配它们。

注意:目前,仅支持条件格式设置规则的子集。具体来说,只有格式规则不需要 <extLst&gt 元素内的 XML 呈现。这意味着不支持数据集和三个特定的图标集(3Triangles,3Stars,5Boxes)。

// 根据行和列为偶数或奇数向 A1:E7 添加一个棋盘图案
worksheet.addConditionalFormatting({
  ref: 'A1:E7',
  rules: [
    {
      type: 'expression',
      formulae: ['MOD(ROW()+COLUMN(),2)=0'],
      style: {fill: {type: 'pattern', pattern: 'solid', bgColor: {argb: 'FF00FF00'}}},
    }
  ]
})

支持的条件格式设置规则类型

类型 描述
expression 任何自定义功能均可用于激活规则。
cellIs 使用指定的运算符将单元格值与提供的公式进行比较
top10 将格式化应用于值在顶部(或底部)范围内的单元格
aboveAverage 将格式化应用于值高于(或低于)平均值的单元格
colorScale 根据其值在范围内的位置将彩色背景应用于单元格
iconSet 根据值将一系列图标之一添加到单元格
containsText 根据单元格是否为特定文本来应用格式
timePeriod 根据单元格日期时间值是否在指定范围内应用格式

表达式

属性 可选 默认值 描述
type 'expression'
priority Y <auto> 确定样式的优先顺序
formulae 1个包含真/假值的公式字符串数组。要引用单元格值,请使用左上角的单元格地址
style 公式返回 true 时要应用的样式结构

Cell Is

属性 可选 默认值 描述
type 'cellIs'
priority Y <auto> 确定样式的优先顺序
operator 如何将单元格值与公式结果进行比较
formulae 1个公式字符串数组,返回要与每个单元格进行比较的值
style 如果比较返回 true,则应用样式结构

Cell Is 运算符

运算 描述
equal 如果单元格值等于公式值,则应用格式
greaterThan 如果单元格值大于公式值,则应用格式
lessThan 如果单元格值小于公式值,则应用格式
between 如果单元格值在两个公式值之间(包括两个值),则应用格式

Top 10

属性 可选 默认值 描述
type 'top10'
priority Y <auto> 确定样式的优先顺序
rank Y 10 指定格式中包含多少个顶部(或底部)值
percent Y false 如果为 true,则等级字段为百分比,而不是绝对值
bottom Y false 如果为 true,则包含最低值而不是最高值
style 如果比较返回 true,则应用样式结构

高于平均值

属性 可选 默认值 描述
type 'aboveAverage'
priority Y <auto> 确定样式的优先顺序
aboveAverage Y false 如果为 true,则等级字段为百分比,而不是绝对值
style 如果比较返回 true,则应用样式结构

色阶

属性 可选 默认值 描述
type 'colorScale'
priority Y <auto> 确定样式的优先顺序
cfvo 2到5个条件格式化值对象的数组,指定值范围内的航路点
color 在给定的航路点使用的相应颜色数组
style 如果比较返回 true,则应用样式结构

图标集

属性 可选 默认值 描述
type 'iconSet'
priority Y <auto> 确定样式的优先顺序
iconSet Y 3TrafficLights 设置使用的图标名称
showValue true 指定应用范围内的单元格是显示图标和单元格值,还是仅显示图标
reverse false 指定是否以保留顺序显示 iconSet 中指定的图标集中的图标。 如果 custom 等于 true,则必须忽略此值
custom false 指定是否使用自定义图标集
cfvo 2到5个条件格式化值对象的数组,指定值范围内的航路点
style 如果比较返回 true,则应用样式结构

数据条

字段 可选 默认值 描述
type 'dataBar'
priority Y <auto> 确定样式的优先顺序
minLength 0 指定此条件格式范围内最短数据条的长度
maxLength 100 指定此条件格式范围内最长数据条的长度
showValue true 指定条件格式范围内的单元格是否同时显示数据条和数值或数据条
gradient true 指定数据条是否具有渐变填充
border true 指定数据条是否有边框
negativeBarColorSameAsPositive true 指定数据条是否具有与正条颜色不同的负条颜色
negativeBarBorderColorSameAsPositive true 指定数据条的负边框颜色是否不同于正边框颜色
axisPosition 'auto' 指定数据条的轴位置
direction 'leftToRight' 指定数据条的方向
cfvo 2 到 5 个条件格式化值对象的数组,指定值范围内的航路点
style 如果比较返回 true,则应用样式结构

包含文字

属性 可选 默认值 描述
type 'containsText'
priority Y <auto> 确定样式的优先顺序
operator 文本比较类型
text 要搜索的文本
style 如果比较返回 true,则应用样式结构

包含文本运算符

运算符 描述
containsText 如果单元格值包含在 text 字段中指定的值,则应用格式
containsBlanks 如果单元格值包含空格,则应用格式
notContainsBlanks 如果单元格值不包含空格,则应用格式
containsErrors 如果单元格值包含错误,则应用格式
notContainsErrors 如果单元格值不包含错误,则应用格式

时间段

属性 可选 默认值 描述
type 'timePeriod'
priority Y <auto> 确定样式的优先顺序
timePeriod 比较单元格值的时间段
style 如果比较返回 true,则应用样式结构

时间段

时间段 描述
lastWeek 如果单元格值落在最后一周内,则应用格式
thisWeek 如果单元格值在本周下降,则应用格式
nextWeek 如果单元格值在下一周下降,则应用格式
yesterday 如果单元格值等于昨天,则应用格式
today 如果单元格值等于今天,则应用格式
tomorrow 如果单元格值等于明天,则应用格式
last7Days 如果单元格值在过去7天之内,则应用格式
lastMonth 如果单元格值属于上个月,则应用格式
thisMonth 如果单元格值在本月下降,则应用格式
nextMonth 如果单元格值在下个月下降,则应用格式

大纲级别

Excel 支持大纲;行或列可以根据用户希望查看的详细程度展开或折叠。

大纲级别可以在列设置中定义:

worksheet.columns = [
  { header: 'Id', key: 'id', width: 10 },
  { header: 'Name', key: 'name', width: 32 },
  { header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1 }
];

或直接在行或列上

worksheet.getColumn(3).outlineLevel = 1;
worksheet.getRow(3).outlineLevel = 1;

工作表大纲级别可以在工作表上设置

// 设置列大纲级别
worksheet.properties.outlineLevelCol = 1;

// 设置行大纲级别
worksheet.properties.outlineLevelRow = 1;

注意:调整行或列上的大纲级别或工作表上的大纲级别将产生副作用,即还修改受属性更改影响的所有行或列的折叠属性。 例如。:

worksheet.properties.outlineLevelCol = 1;

worksheet.getColumn(3).outlineLevel = 1;
expect(worksheet.getColumn(3).collapsed).to.be.true;

worksheet.properties.outlineLevelCol = 2;
expect(worksheet.getColumn(3).collapsed).to.be.false;

大纲属性可以在工作表上设置

worksheet.properties.outlineProperties = {
  summaryBelow: false,
  summaryRight: false,
};

图片

将图像添加到工作表是一个分为两个步骤的过程。首先,通过 addImage() 函数将图像添加到工作簿中,该函数还将返回 imageId 值。然后,使用 imageId,可以将图像作为平铺背景或覆盖单元格区域添加到工作表中。

注意:从此版本开始,不支持调整或变换图像。

将图片添加到工作簿

Workbook.addImage 函数支持按文件名或按 Buffer 添加图像。请注意,在两种情况下,都必须指定扩展名。有效的扩展名包括 “jpeg”,“png”,“gif”。

// 通过文件名将图像添加到工作簿
const imageId1 = workbook.addImage({
  filename: 'path/to/image.jpg',
  extension: 'jpeg',
});

// 通过 buffer 将图像添加到工作簿
const imageId2 = workbook.addImage({
  buffer: fs.readFileSync('path/to.image.png'),
  extension: 'png',
});

// 通过 base64  将图像添加到工作簿
const myBase64Image = "data:image/png;base64,iVBORw0KG...";
const imageId2 = workbook.addImage({
  base64: myBase64Image,
  extension: 'png',
});

将图片添加到工作表背景

使用 Workbook.addImage 中的图像 ID,可以使用 addBackgroundImage 函数设置工作表的背景

// 设置背景
worksheet.addBackgroundImage(imageId1);

在一定范围内添加图片

使用 Workbook.addImage 中的图像 ID,可以将图像嵌入工作表中以覆盖一定范围。从该范围计算出的坐标将覆盖从第一个单元格的左上角到第二个单元格的右下角。

// 在 B2:D6 上插入图片
worksheet.addImage(imageId2, 'B2:D6');

使用结构而不是范围字符串,可以部分覆盖单元格。

请注意,为此使用的坐标系基于零,因此 A1 的左上角将为 {col:0,row:0}。单元格的分数可以通过使用浮点数来指定,例如 A1 的中点是 {col:0.5,row:0.5}

// 在 B2:D6 的一部分上插入图像
worksheet.addImage(imageId2, {
  tl: { col: 1.5, row: 1.5 },
  br: { col: 3.5, row: 5.5 }
});

单元格区域还可以具有属性 "editAs",该属性将控制将图像锚定到单元格的方式。它可以具有以下值之一:

描述
undefined 它指定使图像将根据单元格移动和调整其大小
oneCell 这是默认值。图像将与单元格一起移动,但大小不变动
absolute 图像将不会随着单元格移动或调整大小
ws.addImage(imageId, {
  tl: { col: 0.1125, row: 0.4 },
  br: { col: 2.101046875, row: 3.4 },
  editAs: 'oneCell'
});

将图片添加到单元格

您可以将图像添加到单元格,然后以 96dpi 定义其宽度和高度(以像素为单位)。

worksheet.addImage(imageId2, {
  tl: { col: 0, row: 0 },
  ext: { width: 500, height: 200 }
});

添加带有超链接的图片

您可以将带有超链接的图像添加到单元格,并在图像范围内定义超链接。

worksheet.addImage(imageId2, {
  tl: { col: 0, row: 0 },
  ext: { width: 500, height: 200 },
  hyperlinks: {
    hyperlink: 'http://www.somewhere.com',
    tooltip: 'http://www.somewhere.com'
  }
});

工作表保护

可以通过添加密码来保护工作表免受修改。

await worksheet.protect('the-password', options);

工作表保护也可以删除:

worksheet.unprotect();

有关如何修改单个单元格保护的详细信息请查看 单元格保护

注意:protect() 函数返回一个 Promise 代表它是异步的,当前的实现在主线程上运行,并且在 CPU 上将使用平均大约 600 毫秒。可以通过设置 spinCount 进行调整,该值可用于使过程更快或更有弹性。

工作表保护选项

属性 默认值 描述
selectLockedCells true 允许用户选择锁定的单元格
selectUnlockedCells true 允许用户选择未锁定的单元格
formatCells false 允许用户格式化单元格
formatColumns false 允许用户格式化列
formatRows false 允许用户格式化行
insertRows false 允许用户插入行
insertColumns false 允许用户插入列
insertHyperlinks false 允许用户插入超链接
deleteRows false 允许用户删除行
deleteColumns false 允许用户删除列
sort false 允许用户对数据进行排序
autoFilter false 允许用户过滤表中的数据
pivotTables false 允许用户使用数据透视表
spinCount 100000 保护或取消保护时执行的哈希迭代次数

文件 I/O

XLSX

读 XLSX

读取xlsx文件的可选参数Option如下

Field Required Type Description
ignoreNodes N array 读取xlsx文件时要忽略的xml节点数组,用于提高性能.
节点名有这些: sheetPr, dimension, sheetViews , sheetFormatPr, cols , sheetData, autoFilter , mergeCells , rowBreaks, hyperlinks , pageMargins, dataValidations, pageSetup, headerFooter , printOptions , picture, drawing, sheetProtection, tableParts , conditionalFormatting, extLst,
password N string 解密用的密码,最大长度是255个字符.
base64 N boolean 传入的是否是base64编码的内容,只在load方法时有这个参数.
maxRows N number TODO:.
maxCols N number TODO:.
// 从文件读取
const workbook = new Excel.Workbook();
await workbook.xlsx.readFile(filename);

// 从文件读取, 解密使用密码加密的excel文件
const workbook = new Excel.Workbook();
await workbook.xlsx.readFile(filename, {password:'123456'});
await workbook.xlsx.readFile(filename, {
  ignoreNodes:['dataValidations']  // 忽略工作簿的数据有限性验证节点
});
// ... 使用 workbook


// 从流读取
const workbook = new Excel.Workbook();
await workbook.xlsx.read(stream);

// 从流读取, 解密使用密码加密的excel文件
const workbook = new Excel.Workbook();
await workbook.xlsx.read(stream, {password:'123456'});
await workbook.xlsx.read(stream, {
  ignoreNodes:['dataValidations']  // 忽略工作簿的数据有限性验证节点
});
// ... 使用 workbook


// 从 buffer 加载
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data);

// 从 buffer 加载, 解密使用密码加密的excel文件
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data, {password:'123456'});
await workbook.xlsx.load(data, {
  ignoreNodes:['dataValidations']  // 忽略工作簿的数据有限性验证节点
});
// ... 使用 workbook

写 XLSX

// 写入文件
const workbook = createAndFillWorkbook();
await workbook.xlsx.writeFile(filename);

// 写入文件, 带密码保护的
const workbook = createAndFillWorkbook();
await workbook.xlsx.writeFile(filename, {password: '123456'});

// 写入流
await workbook.xlsx.write(stream);

// 写入流, 带密码保护的
await workbook.xlsx.write(stream, {password: '123456'}));

// 写入 buffer
const buffer = await workbook.xlsx.writeBuffer();

// 写入 buffer, 带密码保护的
const buffer = await workbook.xlsx.writeBuffer({password: '123456'});

CSV

读 CSV

读取 CSV 文件时支持的选项。

属性 是否需要 类型 描述
dateFormats N Array 指定 dayjs 的日期编码格式。
map N Function 自定义Array.prototype.map() 回调函数,用于处理数据。
sheetName N String 指定工作表名称。
parserOptions N Object parseOptions 选项 @fast-csv/format 模块以写入 csv 数据。
// 从文件读取
const workbook = new Excel.Workbook();
const worksheet = await workbook.csv.readFile(filename);
// ... 使用 workbook 或 worksheet


// 从流中读取
const workbook = new Excel.Workbook();
const worksheet = await workbook.csv.read(stream);
// ... 使用 workbook 或 worksheet


// 从带有欧洲日期的文件中读取
const workbook = new Excel.Workbook();
const options = {
  dateFormats: ['DD/MM/YYYY']
};
const worksheet = await workbook.csv.readFile(filename, options);
// ... 使用 workbook 或 worksheet


// 从具有自定义值解析的文件中读取
const workbook = new Excel.Workbook();
const options = {
  map(value, index) {
    switch(index) {
      case 0:
        // 第1列是字符串
        return value;
      case 1:
        // 第2列是日期
        return new Date(value);
      case 2:
        // 第3列是公式值的JSON
        return JSON.parse(value);
      default:
        // 其余的是数字
        return parseFloat(value);
    }
  },
  // https://c2fo.github.io/fast-csv/docs/parsing/options
  parserOptions: {
    delimiter: '\t',
    quote: false,
  },
};
const worksheet = await workbook.csv.readFile(filename, options);
// ... 使用 workbook 或 worksheet

CSV 解析器使用 fast-csv 读取CSV文件。传递给上述写入函数的选项中的 formatterOptions 将传递给 @fast-csv/format 模块以写入 csv 数据。 有关详细信息,请参阅 fast-csv README.md。

使用 npm 模块 dayjs 解析日期。如果未提供 dateFormats 数组,则使用以下 dateFormats:

  • 'YYYY-MM-DD[T]HH:mm:ss'
  • 'MM-DD-YYYY'
  • 'YYYY-MM-DD'

请参阅 dayjs CustomParseFormat 插件,以获取有关如何构造 dateFormat 的详细信息。

写 CSV

写入 CSV 文件时支持的选项。

属性 是否需要 类型 描述
dateFormat N String 指定 dayjs 的日期编码格式。
dateUTC N Boolean 指定 ExcelJS 是否使用dayjs.utc()转换时区以解析日期。
encoding N String 指定文件编码格式。
includeEmptyRows N Boolean 指定是否可以写入空行。
map N Function 自定义Array.prototype.map() 回调函数,用于处理行值。
sheetName N String 指定工作表名称。
sheetId N Number 指定工作表 ID。
formatterOptions N Object formatterOptions 选项 @fast-csv/format 模块写入csv 数据。
// 写入文件
const workbook = createAndFillWorkbook();
await workbook.csv.writeFile(filename);

// 写入流
// 请注意,您需要提供 sheetName 或 sheetId 以正确导入到 csv
await workbook.csv.write(stream, { sheetName: 'Page name' });

// 使用欧洲日期时间写入文件
const workbook = new Excel.Workbook();
const options = {
  dateFormat: 'DD/MM/YYYY HH:mm:ss',
  dateUTC: true, // 呈现日期时使用 utc
};
await workbook.csv.writeFile(filename, options);


// 使用自定义值格式写入文件
const workbook = new Excel.Workbook();
const options = {
  map(value, index) {
    switch(index) {
      case 0:
        // 第1列是字符串
        return value;
      case 1:
        // 第2列是日期
        return dayjs(value).format('YYYY-MM-DD');
      case 2:
        // 第3列是一个公式,只写结果
        return value.result;
      default:
        // 其余的是数字
        return value;
    }
  },
  // https://c2fo.github.io/fast-csv/docs/formatting/options
  formatterOptions: {
    delimiter: '\t',
    quote: false,
  },
};
await workbook.csv.writeFile(filename, options);

// 写入新 buffer
const buffer = await workbook.csv.writeBuffer();

CSV 解析器使用 fast-csv 编写 CSV 文件。传递给上述写入函数的选项中的 formatterOptions 将传递给 @fast-csv/format 模块以写入 csv 数据。有关详细信息,请参阅 fast-csv README.md。

日期使用 npm 模块 dayjs 格式化。如果未提供 dateFormat,则使用 dayjs.ISO_8601。编写 CSV 时,您可以提供布尔值 dateUTCtrue,以使 ExcelJS 解析日期,而无需使用 dayjs.utc() 自动转换时区。

流式 I/O

上面记录的文件 I/O 需要在内存中建立整个工作簿,然后才能写入文件。虽然方便,但是由于所需的内存量,它可能会限制文档的大小。

流写入器(或读取器)在生成工作簿或工作表数据时对其进行处理,然后将其转换为文件形式。通常,这在内存上效率要高得多,因为最终的内存占用量,甚至中间的内存占用量都比文档版本要紧凑得多,尤其是当您考虑到行和单元格对象一旦提交就被销毁时,尤其如此。

流式工作簿和工作表的接口几乎与文档版本相同,但实际存在一些细微差别:

  • 将工作表添加到工作簿后,将无法将其删除。
  • 提交行后,将无法再访问该行,因为该行将从工作表中删除。
  • 不支持 unMergeCells()

请注意,可以在不提交任何行的情况下构建整个工作簿。提交工作簿后,所有添加的工作表(包括所有未提交的行)将自动提交。但是,在这种情况下,与文档版本相比收效甚微。

流式 XLSX

流式 XLSX 写入器

流式 XLSX 写入器在 ExcelJS.stream.xlsx 命名空间中可用。

构造函数采用带有以下字段的可选 options 对象:

字段 描述
stream 指定要写入 XLSX 工作簿的可写流。
filename 如果未指定流,则此字段指定要写入 XLSX 工作簿的文件的路径。
useSharedStrings 指定是否在工作簿中使用共享字符串。默认为 false
useStyles 指定是否将样式信息添加到工作簿。样式会增加一些性能开销。默认为 false
zip ExcelJS 内部传递给 ArchiverZip选项。默认值为 undefined

如果在选项中未指定 streamfilename,则工作簿编写器将创建一个 StreamBuf 对象,该对象将 XLSX 工作簿的内容存储在内存中。可以通过属性 workbook.stream 访问此 StreamBuf 对象,该对象可用于通过 stream.read() 直接访问字节,或将内容通过管道传输到另一个流。

// 使用样式和共享字符串构造流式 XLSX 工作簿编写器
const options = {
  filename: './streamed-workbook.xlsx',
  useStyles: true,
  useSharedStrings: true
};
const workbook = new Excel.stream.xlsx.WorkbookWriter(options);

通常,流式 XLSX 写入器的接口与上述文档工作簿(和工作表)相同,实际上行,单元格和样式对象是相同的。

但是有一些区别...

构造

如上所示,WorkbookWriter 通常将要求在构造函数中指定输出流或文件。

提交数据

当工作表行准备就绪时,应将其提交,以便可以释放行对象和内容。通常,这将在添加每一行时完成...

worksheet.addRow({
   id: i,
   name: theName,
   etc: someOtherDetail
}).commit();

WorksheetWriter 在添加行时不提交行的原因是允许单元格跨行合并:

worksheet.mergeCells('A1:B2');
worksheet.getCell('A1').value = 'I am merged';
worksheet.getCell('C1').value = 'I am not';
worksheet.getCell('C2').value = 'Neither am I';
worksheet.getRow(2).commit(); // now rows 1 and two are committed.

每个工作表完成后,还必须提交:

// 完成添加数据。 提交工作表
worksheet.commit();

要完成 XLSX 文档,必须提交工作簿。 如果未提交工作簿中的任何工作表,则将在工作簿提交中自动提交它们。

// 完成 workbook.
await workbook.commit();
// ... 流已被写入
流式 XLSX 阅读器

流式 XLSX 工作簿阅读器可以在ExcelJS.stream.xlsx命名空间中找到。

构造函数包含必需的输入参数和可选的options参数:

Argument Description
input (必需的) 指定从中读取XLSX工作簿的文件或可读流的名称
options (可选的) 指定如何处理读取解析期间发生的事件类型
options.entries 指定是否去触发事件('emit')或者不发出事件('ignore'),默认值是'emit'
options.sharedStrings 指定是否去缓存('cache')共享字符串,将其插入到相应的单元格值中,或者是否去触发('emit')或忽略('ignore')它们,在这两种情况下,单元格值都将是对共享字符串索引的引用。默认值是'cache'
options.hyperlinks 指定是否去缓存超链接('cache'),将其插入到相应的单元格值中,是否去触发('emit')或忽略('ignore')它们。默认值是'cache'
options.styles 指定是否去缓存样式('cache'),将其插入到相应的行或单元格值中,或是否忽略('忽略')它们。默认值是'cache'
options.worksheets 指定是否去触发('emit')或忽略('ignore')工作表。默认值是'emit'
const workbook = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx');
for await (const worksheetReader of workbookReader) {
  for await (const row of worksheetReader) {
    // ...
  }
}

请注意,由于性能原因,worksheetReader返回一个行数组,而不是单独返回每一行: nodejs/node#31979

迭代遍历所有事件

工作簿上的事件是 'worksheet'、'shared-strings' 和 'hyperlinks'。 工作表上的事件是 'row' 和 'hyperlinks'.

const options = {
  sharedStrings: 'emit',
  hyperlinks: 'emit',
  worksheets: 'emit',
};
const workbook = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', options);
for await (const {eventType, value} of workbook.parse()) {
  switch (eventType) {
    case 'shared-strings':
      // 值是共享字符串
    case 'worksheet':
      // 值是worksheetReader
    case 'hyperlinks':
      // 值是hyperlinksReader
  }
}
可读流

我们强烈建议使用异步迭代,但我们也公开了流接口以实现向后兼容性。

const options = {
  sharedStrings: 'emit',
  hyperlinks: 'emit',
  worksheets: 'emit',
};
const workbookReader = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', options);
workbookReader.read();

workbookReader.on('worksheet', worksheet => {
  worksheet.on('row', row => {
  });
});

workbookReader.on('shared-strings', sharedString => {
  // ...
});

workbookReader.on('hyperlinks', hyperlinksReader => {
  // ...
});

workbookReader.on('end', () => {
  // ...
});
workbookReader.on('error', (err) => {
  // ...
});

浏览器

该库的一部分已被隔离,并经过测试可在浏览器环境中使用。

由于工作簿读写器的流式传输性质,因此未包括这些内容。只能使用基于文档的工作簿(有关详细信息,请参见 创建工作簿)。

例如,在浏览器中使用 ExcelJS 的代码可查看 github 中的 spec / browser 文件夹。

预捆绑

以下文件已预先捆绑在一起,并包含在 dist 文件夹中。

  • exceljs.js
  • exceljs.min.js

值类型

支持以下值类型。

Null 值

Enum: Excel.ValueType.Null

空值表示没有值,通常在写入文件时将不存储(合并的单元格除外)。可用于从单元格中删除该值。例如:

worksheet.getCell('A1').value = null;

合并单元格

Enum: Excel.ValueType.Merge

合并单元格是其值绑定到另一个“主”单元格的单元格。分配给合并单元将导致修改单元格。

数字值

Enum: Excel.ValueType.Number

一个数字值。

例如:

worksheet.getCell('A1').value = 5;
worksheet.getCell('A2').value = 3.14159;

字符串值

Enum: Excel.ValueType.String

一个简单的文本字符串。

例如:

worksheet.getCell('A1').value = 'Hello, World!';

日期值

Enum: Excel.ValueType.Date

日期值,由 JavaScript Date 类型表示。

例如:

worksheet.getCell('A1').value = new Date(2017, 2, 15);

超链接值

Enum: Excel.ValueType.Hyperlink

具有文本和链接值的 URL。

例如:

// 链接到网络
worksheet.getCell('A1').value = {
  text: 'www.mylink.com',
  hyperlink: 'http://www.mylink.com',
  tooltip: 'www.mylink.com'
};

// 内部链接
worksheet.getCell('A1').value = { text: 'Sheet2', hyperlink: '#\'Sheet2\'!A1' };

公式值

Enum: Excel.ValueType.Formula

一个 Excel 公式,用于即时计算值。请注意,虽然单元格类型将为“公式”,但该单元格可能具有一个有效类型值,该值将从结果值中得出。

请注意,ExcelJS 无法处理公式以生成结果,必须提供该公式。

例如:

worksheet.getCell('A3').value = { formula: 'A1+A2', result: 7 };

单元格还支持便捷的获取器,以访问公式和结果:

worksheet.getCell('A3').formula === 'A1+A2';
worksheet.getCell('A3').result === 7;

共享公式

共享的公式通过减少工作表 xml 中文本的重复来增强 xlsx 文档的压缩。范围中左上角的单元格是指定的母版,它将保留该范围内的所有其他单元格都将引用的公式。然后,其他“从属”单元格可以引用此主单元格,而不必再次重新定义整个公式。请注意,主公式将以常用的 Excel 方式转换为从属单元格,以便对其他单元格的引用将根据从属单元相对于主单元的偏移量向右下移。例如:如果主单元格A2具有引用A1的公式,则如果单元格B2共享A2的公式,则它将引用B1。

可以将主公式与该范围内的从属单元格一起分配给该单元格

worksheet.getCell('A2').value = {
  formula: 'A1',
  result: 10,
  shareType: 'shared',
  ref: 'A2:B3'
};

可以使用新的值形式将共享公式分配给单元格:

worksheet.getCell('B2').value = { sharedFormula: 'A2', result: 10 };

这指定单元格B2是将从A2中的公式派生的公式,其结果为10。

公式便捷获取器会将A2中的公式转换为B2中应具有的公式:

expect(worksheet.getCell('B2').formula).to.equal('B1');

可以使用 fillFormula 方法将共享的公式分配到工作表中:

// 将 A1 设置为起始编号
worksheet.getCell('A1').value = 1;

// 从 A1 开始以递增计数将 A2 填充到 A10
worksheet.fillFormula('A2:A10', 'A1+1', [2,3,4,5,6,7,8,9,10]);

fillFormula 也可以使用回调函数来计算每个单元格的值

// 从A1开始以递增计数将 A2 填充到 A100
worksheet.fillFormula('A2:A100', 'A1+1', (row, col) => row);

公式类型

要区分真正的和转换后的公式单元格,请使用 FormulaType getter:

worksheet.getCell('A3').formulaType === Enums.FormulaType.Master;
worksheet.getCell('B3').formulaType === Enums.FormulaType.Shared;

公式类型具有以下值:

名称
Enums.FormulaType.None 0
Enums.FormulaType.Master 1
Enums.FormulaType.Shared 2

数组公式

在 Excel 中表示共享公式的一种新方法是数组公式。以这种形式,主单元格是唯一包含与公式有关的任何信息的单元格。它包含 shareType 'array' 以及适用于其的单元格范围以及将要复制的公式。其余单元格是具有常规值的常规单元格。

注意:数组公式不会以共享公式的方式转换。因此,如果主单元A2引用A1,则从单元B2也将引用A1。

例如:

// 将数组公式分配给 A2:B3
worksheet.getCell('A2').value = {
  formula: 'A1',
  result: 10,
  shareType: 'array',
  ref: 'A2:B3'
};

// 可能没有必要填写工作表中的其余值

fillFormula 方法也可以用于填充数组公式

// 用数组公式 "A1" 填充 A2:B3
worksheet.fillFormula('A2:B3', 'A1', [1,1,1,1], 'array');

富文本值

Enum: Excel.ValueType.RichText

样式丰富的文本。

例如:

worksheet.getCell('A1').value = {
  richText: [
    { text: 'This is '},
    {font: {italic: true}, text: 'italic'},
  ]
};

布尔值

Enum: Excel.ValueType.Boolean

例如:

worksheet.getCell('A1').value = true;
worksheet.getCell('A2').value = false;

错误值

Enum: Excel.ValueType.Error

例如:

worksheet.getCell('A1').value = { error: '#N/A' };
worksheet.getCell('A2').value = { error: '#VALUE!' };

当前有效的错误文本值为:

名称
Excel.ErrorValue.NotApplicable #N/A
Excel.ErrorValue.Ref #REF!
Excel.ErrorValue.Name #NAME?
Excel.ErrorValue.DivZero #DIV/0!
Excel.ErrorValue.Null #NULL!
Excel.ErrorValue.Value #VALUE!
Excel.ErrorValue.Num #NUM!

接口变化

我们会尽一切努力创建一个良好的,一致的接口,该接口不会在版本之间不兼容,但令人遗憾的是,为了实现更大的利益,有时需要进行一些更改。

0.1.0

Worksheet.eachRow

Worksheet.eachRow 的回调函数中的参数已被交换和更改;它是 function(rowNumber,rowValues),现在是 function(row,rowNumber),使它的外观更像 underscore(_.each)方法,并且行对象优先于行号。

Worksheet.getRow

此函数已从返回稀疏的单元格数组更改为返回 Row 对象。这样可以访问行属性,并有助于管理行样式等。

仍可通过 Worksheet.getRow(rowNumber).values; 获得稀疏的单元格值的数组。

0.1.1

cell.model

cell.styles 重命名为 cell.style

0.2.44

从 Bluebird 切换到 Node 原生 Promise 的函数返回的 Promise 如果依赖 Bluebird 的额外功能,则可能会破坏调用代码。

为了减少这种情况的出现,在0.3.0中添加了以下两个更改:

  • 默认情况下使用功能更全且仍与浏览器兼容的 promise lib。 该库支持 Bluebird 的许多功能,但占用空间少得多。
  • 注入其他 Promise 实现的选项。有关更多详细信息,请参见配置部分。

配置

ExcelJS现在支持对 Promise 库的依赖项注入。您可以通过在模块中包含以下代码来还原 Bluebird Promise。

ExcelJS.config.setValue('promise', require('bluebird'));

请注意:我已经使用 bluebird 专门测试了 ExcelJS(直到最近,这是它使用的库)。根据我所做的测试,它不适用于 Q。

注意事项

Dist 文件夹

在发布此模块之前,先对源代码进行编译和其他处理,然后再将它们放置在 dist/ 文件夹中。该自述文件标识两个文件-浏览器捆绑和压缩版本。除了在 package.json 中指定为 "main" 的文件外,不能保证 dist/ 文件夹的其他内容。

已知的问题

使用 Puppeteer 进行测试

该 lib 中包含的测试套件包括一个在无头浏览器中执行的小脚本,以验证捆绑的软件包。 在撰写本文时,其表现出该测试在 Windows Linux 子系统中不能很好地进行。

因此,可以通过存在名为 .disable-test-browser 的文件来禁用浏览器测试。

sudo apt-get install libfontconfig

拼接与合并

如果任何 splice 操作影响合并的单元格,则合并组将无法正确移动

发布历史

版本 变化
0.0.9
0.1.0
0.1.1
  • Bug 修复
    • 可以将更多文本数据正确写入xml(包括文本,超链接,公式结果和格式代码)
    • 更好的日期格式代码识别
  • 单元格字体样式
0.1.2
  • 修复了 zip 写入时潜在的竞争条件
0.1.3
0.1.5
  • Bug 修复
    • 现在可以在一本工作簿中处理10个或更多工作表
    • 正确添加并引用了 theme1.xml 文件
  • 单元格边框
0.1.6
0.1.8
  • Bug 修复
    • XLSX 文件中包含更兼容的theme1.xml
    • 修复文件名大小写问题
  • 单元格填充
0.1.9
  • Bug 修复
    • 添加了 docProps 文件以满足 Mac Excel 用户
    • 修复文件名大小写问题
    • 修复工作表 ID 问题
  • 核心工作簿属性
0.1.10
0.1.11
0.2.0
  • Streaming XLSX Writer
    • At long last ExcelJS can support writing massive XLSX files in a scalable memory efficient manner. Performance has been optimised and even smaller spreadsheets can be faster to write than the document writer. Options have been added to control the use of shared strings and styles as these can both have a considerable effect on performance
  • Worksheet.lastRow
    • Access the last editable row in a worksheet.
  • Row.commit()
    • For streaming writers, this method commits the row (and any previous rows) to the stream. Committed rows will no longer be editable (and are typically deleted from the worksheet object). For Document type workbooks, this method has no effect.
0.2.2
  • One Billion Cells
    • Achievement Unlocked: A simple test using ExcelJS has created a spreadsheet with 1,000,000,000 cells. Made using random data with 100,000,000 rows of 10 cells per row. I cannot validate the file yet as Excel will not open it and I have yet to implement the streaming reader but I have every confidence that it is good since 1,000,000 rows loads ok.
0.2.3
  • Bug Fixes
  • Streaming XLSX Writer
    • At long last ExcelJS can support writing massive XLSX files in a scalable memory efficient manner. Performance has been optimised and even smaller spreadsheets can be faster to write than the document writer. Options have been added to control the use of shared strings and styles as these can both have a considerable effect on performance
  • Worksheet.lastRow
    • Access the last editable row in a worksheet.
  • Row.commit()
    • For streaming writers, this method commits the row (and any previous rows) to the stream. Committed rows will no longer be editable (and are typically deleted from the worksheet object). For Document type workbooks, this method has no effect.
0.2.4
0.2.6
0.2.7
  • Data Validations
    • Cells can now define validations that controls the valid values the cell can have
0.2.8
0.2.9
  • Fixed "read property 'richText' of undefined error. Thanks to james075
0.2.10
  • Refactoring Complete. All unit and integration tests pass.
0.2.11
0.2.12
0.2.13
0.2.14
0.2.15
0.2.16
0.2.17
0.2.18
0.2.19
0.2.20
0.2.21
0.2.22
0.2.23
  • Merged Fall back to JSON.stringify() if unknown Cell.Type #137 with some modification. If a cell value is assigned to an unrecognisable javascript object, the stored value in xlsx and csv files will be JSON stringified. Note that if the file is read again, no attempt will be made to parse the stringified JSON text. Thanks to wulfsolter for the contribution.
0.2.24
  • Merged Protect cell fix #166. This does not mean full support for protected cells merely that the parser is not confused by the extra xml. Thanks to jayflo for the contribution.
0.2.25
  • Added functions to delete cells, rows and columns from a worksheet. Modelled after the Array splice method, the functions allow cells, rows and columns to be deleted (and optionally inserted). See Columns and Rows for details.
    Note: Not compatible with cell merges
0.2.26
0.2.27
0.2.28
0.2.29
0.2.30
  • Merged Fix issue #178 #201. Adds the following properties to workbook:
    • title
    • subject
    • keywords
    • category
    • description
    • company
    • manager
    Thanks to stavenko for the contribution.
0.2.31
0.2.32
0.2.33
0.2.34
0.2.35
0.2.36
0.2.37
0.2.38
0.2.39
0.2.42
  • Browser Compatible!
    • Well mostly. I have added a browser sub-folder that contains a browserified bundle and an index.js that can be used to generate another. See Browser section for details.
  • Fixed corrupted theme.xml. Apologies for letting that through.
  • Merged [BUGFIX] data validation formulae undefined #253. Thanks to jayflo for the contribution.
0.2.43
0.2.44
  • Reduced Dependencies.
    • Goodbye lodash, goodbye bluebird. Minified bundle is now just over half what it was in the first version.
0.2.45
0.2.46
0.3.0
0.3.1
0.4.0
0.4.1
0.4.2
  • Addressed the following issues:

    These issues are potentially caused by a bug that caused colours with zero themes, tints or indexes to be rendered and parsed incorrectly.

    Regarding themes: the theme files stored inside the xlsx container hold important information regarding colours, styles etc and if the theme information from a loaded xlsx file is lost, the results can be unpredictable and undesirable. To address this, when an ExcelJS Workbook parses an XLSX file, it will preserve any theme files it finds and include them when writing to a new XLSX. If this behaviour is not desired, the Workbook class exposes a clearThemes() function which will drop the theme content. Note that this behaviour is only implemented in the document based Workbook class, not the streamed Reader and Writer.

0.4.3
0.4.4
0.4.6
0.4.9
  • Switching to transpiled code for distribution. This will ensure compatability with 4.0.0 and above from here on. And it will also allow use of much more expressive JS code in the lib folder!
  • Basic Image Support!Images can now be added to worksheets either as a tiled background or stretched over a range. Note: other features like rotation, etc. are not supported yet and will reqeuire further work.
0.4.10
0.4.11
0.4.12
0.4.13
0.4.14
0.5.0
0.5.1
0.6.0
0.6.1
0.6.2
0.7.0
0.7.1
0.8.0
0.8.1
0.8.2
0.8.3
0.8.4
0.8.5
0.9.0
0.9.1
1.0.0
1.0.1
1.0.2
1.1.0
1.1.1
1.1.2
1.1.3
1.2.0
1.2.1
1.3.0
1.4.2
1.4.3
1.4.5
1.4.6
1.4.7
1.4.8
1.4.9
1.4.10
1.4.12
1.4.13
1.5.0
1.5.1
1.6.0
1.6.1
1.6.2
1.6.3
1.7.0
1.8.0
1.9.0
1.9.1
1.10.0
1.11.0
1.12.0
1.12.1
1.12.2
1.13.0
1.14.0
1.15.0
2.0.1

Major Version Change

Introducing async/await to ExcelJS!

The new async and await features of JavaScript can help a lot to make code more readable and maintainable. To avoid confusion, particularly with returned promises from async functions, we have had to remove the Promise class configuration option and from v2 onwards ExcelJS will use native Promises. Since this is potentially a breaking change we're bumping the major version for this release.

Changes

3.0.0

Another Major Version Change

Javascript has changed a lot over the years, and so have the modules and technologies surrounding it. To this end, this major version of ExcelJS changes the structure of the publish artefacts:

Main Export is now the Original Javascript Source

Prior to this release, the transpiled ES5 code was exported as the package main. From now on, the package main comes directly from the lib/ folder. This means a number of dependencies have been removed, including the polyfills.

ES5 and Browserify are Still Included

In order to support those that still require ES5 ready code (e.g. as dependencies in web apps) the source code will still be transpiled and available in dist/es5.

The ES5 code is also browserified and available as dist/exceljs.js or dist/exceljs.min.js

See the section Importing for details

3.1.0
3.2.0
3.3.0
3.3.1
3.4.0
3.5.0
  • Conditional Formatting A subset of Excel Conditional formatting has been implemented! Specifically the formatting rules that do not require XML to be rendered inside an <extLst> node, or in other words everything except databar and three icon sets (3Triangles, 3Stars, 5Boxes). These will be implemented in due course
  • Merged remove core-js/ import #1030. Many thanks to jeffrey n. carre for this contribution. This change is used to create a new browserified bundle artefact that does not include any polyfills. See Browserify for details.
3.6.0
3.6.1
3.7.0
3.8.0
3.8.1
3.8.2