exceljs
Version:
Excel Workbook Manager - Read and Write xlsx and csv Files.
1,573 lines (1,233 loc) • 199 kB
Markdown
# ExcelJS
[](https://github.com/exceljs/exceljs/actions?query=workflow%3AExcelJS)
[](https://lgtm.com/projects/g/exceljs/exceljs/context:javascript)
[](https://lgtm.com/projects/g/exceljs/exceljs/alerts)
读取,操作并写入电子表格数据和样式到 XLSX 和 JSON 文件。
一个 Excel 电子表格文件逆向工程项目。
# 安装
```shell
npm install exceljs
```
# 新的功能!
* Merged [fix: styles rendering in case when "numFmt" is present in conditional formatting rules (resolves #1814) #1815](https://github.com/exceljs/exceljs/pull/1815). <br/> Many thanks to [@andreykrupskii](https://github.com/andreykrupskii) for this contribution!
* Merged [inlineStr cell type support #1575 #1576](https://github.com/exceljs/exceljs/pull/1576). <br/> Many thanks to [@drdmitry](https://github.com/drdmitry) for this contribution!
* Merged [Fix parsing of boolean attributes #1849](https://github.com/exceljs/exceljs/pull/1849). <br/> Many thanks to [@bno1](https://github.com/bno1) for this contribution!
* Merged [add optional custom auto-filter to table #1670](https://github.com/exceljs/exceljs/pull/1670). <br/> Many thanks to [@thambley](https://github.com/thambley) for this contribution!
* Merged [Deep copy inherited style #1850](https://github.com/exceljs/exceljs/pull/1850). <br/> Many thanks to [@ikzhr](https://github.com/ikzhr) for this contribution!
* Merged [Upgrade actions/cache and actions/setup-node #1846](https://github.com/exceljs/exceljs/pull/1846). <br/> Many thanks to [@cclauss](https://github.com/cclauss) for this contribution!
* Merged [Check object keys in isEqual #1831](https://github.com/exceljs/exceljs/pull/1831). <br/> Many thanks to [@bno1](https://github.com/bno1) for this contribution!
* Merged [Add v17 to testing workflow #1856](https://github.com/exceljs/exceljs/pull/1856). <br/> Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution!
* Merged [Upgrade jszip to its latest version to date. This version does not have any vulnerability found by Snyk so far #1895](https://github.com/exceljs/exceljs/pull/1895). <br/> Many thanks to [@ValerioSevilla](https://github.com/ValerioSevilla) for this contribution!
* Merged [Update README.md #1677](https://github.com/exceljs/exceljs/pull/1677). <br/> Many thanks to [@xjrcode](https://github.com/xjrcode) for this contribution!
* Merged [(docs): set prototype of RegExp correctly. #1700](https://github.com/exceljs/exceljs/pull/1700). <br/> Many thanks to [@joeldenning](https://github.com/joeldenning) for this contribution!
* Merged [Added timeouts to github actions #1733](https://github.com/exceljs/exceljs/pull/1733). <br/> Many thanks to [@alexbjorlig](https://github.com/alexbjorlig) for this contribution!
* Merged [fix issue 1676 #1701](https://github.com/exceljs/exceljs/pull/1701). <br/> Many thanks to [@skypesky](https://github.com/skypesky) for this contribution!
* Merged [ExcelJS/ExcelJS#2237 : Update CI Tests, Drop support for Node v8 #2242](https://github.com/exceljs/exceljs/pull/2242). <br/> Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution!
* Merged [Fix types for getWorksheet() #2223](https://github.com/exceljs/exceljs/pull/2223). <br/> Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution!
* Merged [add characters cannot be used for worksheet name #2126](https://github.com/exceljs/exceljs/pull/2126). <br/> Many thanks to [@tkm-kj](https://github.com/tkm-kj) for this contribution!
* Merged [Fix issue #1753 Reject promise when workbook reader is writing to temporary file stream and error occurs #1756](https://github.com/exceljs/exceljs/pull/1756). <br/> Many thanks to [@pauliusg](https://github.com/pauliusg) for this contribution!
* Merged [README.md to have correct link for Streaming XLSX #2186](https://github.com/exceljs/exceljs/pull/2186). <br/> Many thanks to [@wulfsolter](https://github.com/wulfsolter) for this contribution!
* Merged [Added a polyfill of promise.finally to support lower versions of Firefox. #1982](https://github.com/exceljs/exceljs/pull/1982). <br/> Many thanks to [@DemoJj](https://github.com/DemoJj) for this contribution!
* Merged [Fix read this.worksheet before assign it #1934](https://github.com/exceljs/exceljs/pull/1934). <br/> Many thanks to [@ZyqGitHub1](https://github.com/ZyqGitHub1) for this contribution!
* Merged [chore: upgrade jszip to ^3.10.1 #2211](https://github.com/exceljs/exceljs/pull/2211). <br/> Many thanks to [@jarrod-cocoon](https://github.com/jarrod-cocoon) for this contribution!
* Merged [fixed spelling error in README.md file #2208](https://github.com/exceljs/exceljs/pull/2208). <br/> Many thanks to [@HugoP27](https://github.com/HugoP27) for this contribution!
* Merged [fix: Fix xlsx.writeFile() not catching error when error occurs #2244](https://github.com/exceljs/exceljs/pull/2244). <br/> Many thanks to [@zurmokeeper](https://github.com/zurmokeeper) for this contribution!
* Merged [Improve worksheets' naming validation logic. #2257](https://github.com/exceljs/exceljs/pull/2257). <br/> Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution!
* Merged [fix issue 2125 - spliceRows remove last row #2140](https://github.com/exceljs/exceljs/pull/2140). <br/> Many thanks to [@babu-ch](https://github.com/babu-ch) for this contribution!
* Merged [fix: fix the loss of column attributes due to incorrect column order #2222](https://github.com/exceljs/exceljs/pull/2222). <br/> Many thanks to [@cpaiyueyue](https://github.com/cpaiyueyue) for this contribution!
* Merged [Fix: Sheet Properties Types #2327](https://github.com/exceljs/exceljs/pull/2327). <br/> Many thanks to [@albeniraouf](https://github.com/albeniraouf) for this contribution!
* Merged [Use node 18 LTS for tsc, and benchmark. Add node 20. to test matrix. … #2354](https://github.com/exceljs/exceljs/pull/2354). <br/> Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution!
* Merged [Add missing tooltip attribute to CellHyperlinkValue index.d.ts #2350](https://github.com/exceljs/exceljs/pull/2350). <br/> Many thanks to [@NiklasPor](https://github.com/NiklasPor) for this contribution!
* Merged [Increase resilience to generating large workbooks #2320](https://github.com/exceljs/exceljs/pull/2320). <br/> Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution!
* Merged [repair all 'c2fo.io' links ('c2fo.github.io') #2324](https://github.com/exceljs/exceljs/pull/2324). <br/> Many thanks to [@justintunev7](https://github.com/justintunev7) for this contribution!
* Merged [fix: fix type definitions about last column, formula values and protection #2309](https://github.com/exceljs/exceljs/pull/2309). <br/> Many thanks to [@gltjk](https://github.com/gltjk) for this contribution!
* Merged [fix: add spinCount field for WorksheetProtection type #2284](https://github.com/exceljs/exceljs/pull/2284). <br/> Many thanks to [@damingerdai](https://github.com/damingerdai) for this contribution!
* Merged [Add type definition for WorksheetModel.merges #2281](https://github.com/exceljs/exceljs/pull/2281). <br/> Many thanks to [@ytjmt](https://github.com/ytjmt) for this contribution!
# 贡献
欢迎贡献!这可以帮助我了解大家需要一些什么功能,或者哪些 bugs 造成了极大的麻烦。
我只有一个请求;如果您提交对错误修复的请求(PR),请添加一个能够解决问题的单元测试或集成测试(在 *spec* 文件夹中)。
即使只是测试失败的请求(PR)也可以 - 我可以分析测试的过程并以此修复代码。
注意:请尽可能避免在请求(PR)中修改软件包版本。
版本一般在发布时会进行更新,任何版本更改很可能导致合并冲突。
明确地说,添加到该库的所有贡献都将包含在该库的 MIT 许可证中。
# 目录
<ul>
<li><a href="#导入">导入</a></li>
<li>
<a href="#接口">接口</a>
<ul>
<li><a href="#创建工作簿">创建工作簿</a></li>
<li><a href="#设置工作簿属性">设置工作簿属性</a></li>
<li><a href="#工作簿视图">工作簿视图</a></li>
<li><a href="#添加工作表">添加工作表</a></li>
<li><a href="#删除工作表">删除工作表</a></li>
<li><a href="#访问工作表">访问工作表</a></li>
<li><a href="#工作表状态">工作表状态</a></li>
<li><a href="#工作表属性">工作表属性</a></li>
<li><a href="#页面设置">页面设置</a></li>
<li><a href="#页眉和页脚">页眉和页脚</a></li>
<li>
<a href="#工作表视图">工作表视图</a>
<ul>
<li><a href="#冻结视图">冻结视图</a></li>
<li><a href="#拆分视图">拆分视图</a></li>
</ul>
</li>
<li><a href="#自动筛选器">自动筛选器</a></li>
<li><a href="#列">列</a></li>
<li><a href="#行">行</a>
<ul>
<li><a href="#add-rows">Add Rows</a></li>
<li><a href="#处理单个单元格">处理单个单元格</a></li>
<li><a href="#合并单元格">合并单元格</a></li>
<li><a href="#insert-rows">Insert Rows</a></li>
<li><a href="#splice">Splice</a></li>
<li><a href="#重复行">重复行</a></li>
</ul>
</li>
<li><a href="#定义名称">定义名称</a></li>
<li><a href="#数据验证">数据验证</a></li>
<li><a href="#单元格注释">单元格注释</a></li>
<li><a href="#表格">表格</a></li>
<li><a href="#样式">样式</a>
<ul>
<li><a href="#数字格式">数字格式</a></li>
<li><a href="#字体">字体</a></li>
<li><a href="#对齐">对齐</a></li>
<li><a href="#边框">边框</a></li>
<li><a href="#填充">填充</a></li>
<li><a href="#富文本">富文本</a></li>
</ul>
</li>
<li><a href="#条件格式化">条件格式化</a></li>
<li><a href="#大纲级别">大纲级别</a></li>
<li><a href="#图片">图片</a></li>
<li><a href="#工作表保护">工作表保护</a></li>
<li><a href="#文件-io">文件 I/O</a>
<ul>
<li><a href="#xlsx">XLSX</a>
<ul>
<li><a href="#读-xlsx">读 XLSX</a></li>
<li><a href="#写-xlsx">写 XLSX</a></li>
</ul>
</li>
<li><a href="#csv">CSV</a>
<ul>
<li><a href="#读-csv">读 CSV</a></li>
<li><a href="#写-csv">写 CSV</a></li>
</ul>
</li>
<li><a href="#流式-io">流式 I/O</a>
<ul>
<li><a href="#流式-xlsx">流式 XLSX</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a href="#浏览器">浏览器</a></li>
<li>
<a href="#值类型">值类型</a>
<ul>
<li><a href="#null-值">Null 值</a></li>
<li><a href="#合并单元格">合并单元格</a></li>
<li><a href="#数字值">数字值</a></li>
<li><a href="#字符串值">字符串值</a></li>
<li><a href="#日期值">日期值</a></li>
<li><a href="#超链接值">超链接值</a></li>
<li>
<a href="#公式值">公式值</a>
<ul>
<li><a href="#共享公式">共享公式</a></li>
<li><a href="#公式类型">公式类型</a></li>
<li><a href="#数组公式">数组公式</a></li>
</ul>
</li>
<li><a href="#富文本值">富文本值</a></li>
<li><a href="#布尔值">布尔值</a></li>
<li><a href="#错误值">错误值</a></li>
</ul>
</li>
<li><a href="#配置">配置</a></li>
<li><a href="#已知的问题">已知的问题</a></li>
<li><a href="#发布历史">发布历史</a></li>
</ul>
# 导入[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
const ExcelJS = require('exceljs');
```
## ES5 导入[⬆](#目录)<!-- Link generated with jump2header -->
要使用 ES5 编译代码,请使用 *dist/es5* 路径。
```javascript
const ExcelJS = require('exceljs/dist/es5');
```
**注意:**ES5 版本对许多 polyfill 都具有隐式依赖,而 exceljs 不再明确添加。
您需要在依赖项中添加 `core-js` 和 `regenerator-runtime`,并在导入 `exceljs` 之前在代码中包含以下引用:
```javascript
// 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 模式。 例如,
```js
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;
}
```
## 浏览器端[⬆](#目录)<!-- Link generated with jump2header -->
ExcelJS 在 *dist/* 文件夹内发布了两个支持浏览器的包:
一个是隐式依赖 `core-js` polyfills 的...
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.js"></script>
<script src="exceljs.js"></script>
```
另一个则没有...
```html
<script src="--your-project's-pollyfills-here--"></script>
<script src="exceljs.bare.js"></script>
```
# 接口[⬆](#目录)<!-- Link generated with jump2header -->
## 创建工作簿[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
const workbook = new ExcelJS.Workbook();
```
## 设置工作簿属性[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
workbook.creator = 'Me';
workbook.lastModifiedBy = 'Her';
workbook.created = new Date(1985, 8, 30);
workbook.modified = new Date();
workbook.lastPrinted = new Date(2016, 9, 27);
```
```javascript
// 将工作簿日期设置为 1904 年日期系统
workbook.properties.date1904 = true;
```
## 设置计算属性[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 在加载时强制工作簿计算属性
workbook.calcProperties.fullCalcOnLoad = true;
```
## 工作簿视图[⬆](#目录)<!-- Link generated with jump2header -->
工作簿视图控制在查看工作簿时 Excel 将打开多少个单独的窗口。
```javascript
workbook.views = [
{
x: 0, y: 0, width: 10000, height: 20000,
firstSheet: 0, activeTab: 1, visibility: 'visible'
}
]
```
## 添加工作表[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
const sheet = workbook.addWorksheet('My Sheet');
```
使用 `addWorksheet` 函数的第二个参数来指定工作表的选项。
示例:
```javascript
// 创建带有红色标签颜色的工作表
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}]});
```
## 删除工作表[⬆](#目录)<!-- Link generated with jump2header -->
使用工作表的 `id` 从工作簿中删除工作表。
示例:
```javascript
// 创建工作表
const sheet = workbook.addWorksheet('My Sheet');
// 使用工作表 id 删除工作表
workbook.removeWorksheet(sheet.id)
```
## 访问工作表[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 遍历所有工作表
// 注意: workbook.worksheets.forEach 仍然是可以正常运行的, 但是以下的方式更好
workbook.eachSheet(function(worksheet, sheetId) {
// ...
});
// 按 name 提取工作表
const worksheet = workbook.getWorksheet('My Sheet');
// 按 id 提取工作表
const worksheet = workbook.getWorksheet(1);
```
## 工作表状态[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 使工作表可见
worksheet.state = 'visible';
// 隐藏工作表
worksheet.state = 'hidden';
// 从“隐藏/取消隐藏”对话框中隐藏工作表
worksheet.state = 'veryHidden';
```
## 工作表属性[⬆](#目录)<!-- Link generated with jump2header -->
工作表支持属性存储,以允许控制工作表的某些功能。
```javascript
// 创建具有属性的新工作表
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 |
### 工作表尺寸[⬆](#目录)<!-- Link generated with jump2header -->
一些新的尺寸属性已添加到工作表中...
| 属性名 | 描述 |
| ----------------- | ------------------------------------------------------------ |
| rowCount | 文档的总行数。 等于具有值的最后一行的行号。 |
| actualRowCount | 具有值的行数的计数。 如果中间文档行为空,则该行将不包括在计数中。 |
| columnCount | 文档的总列数。 等于所有行的最大单元数。 |
| actualColumnCount | 具有值的列数的计数。 |
## 页面设置[⬆](#目录)<!-- Link generated with jump2header -->
所有可能影响工作表打印的属性都保存在工作表上的 `pageSetup` 对象中。
```javascript
// 使用 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 | | 是否使用 `fitToWidth` 和 `fitToHeight` 或 `scale` 设置。默认基于存在于 `pageSetup` 对象中的设置-如果两者都存在,则 `scale` 优先级高(默认值为 `false`)。 |
| pageOrder | `'downThenOver'` | 打印页面的顺序-`['downThenOver', 'overThenDown']` 之一 |
| blackAndWhite | `false` | 无色打印 |
| draft | `false` | 打印质量较低(墨水) |
| cellComments | `'None'` | 在何处放置批注-`['atEnd','asDisplayed','None']`中的一个 |
| errors | `'displayed'` | 哪里显示错误 -`['dash', 'blank', 'NA', 'displayed']` 之一 |
| scale | 100 | 增加或减小打印尺寸的百分比值。 当 `fitToPage` 为 `false` 时激活 |
| fitToWidth | 1 | 纸张应打印多少页宽。 当 `fitToPage` 为 `true` 时激活 |
| fitToHeight | 1 | 纸张应打印多少页高。 当 `fitToPage` 为 `true` 时激活 |
| 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 |
## 页眉和页脚[⬆](#目录)<!-- Link generated with jump2header -->
这是添加页眉和页脚的方法。
添加的内容主要是文本,例如时间,简介,文件信息等,您可以设置文本的样式。
此外,您可以为首页和偶数页设置不同的文本。
注意:目前不支持图片。
```javascript
// 创建一个带有页眉和页脚的工作表
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 |
## 工作表视图[⬆](#目录)<!-- Link generated with jump2header -->
现在,工作表支持视图列表,这些视图控制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` | 演示样式- `pageBreakPreview` 或 `pageLayout` 之一。 注意:页面布局与 `frozen` 视图不兼容 |
### 冻结视图[⬆](#目录)<!-- Link generated with jump2header -->
冻结视图支持以下额外属性:
| 属性名 | 默认值 | 描述 |
| ----------------- | --------- | ----------- |
| xSplit | 0 | 冻结多少列。要仅冻结行,请将其设置为 `0` 或 `undefined` |
| ySplit | 0 | 冻结多少行。要仅冻结列,请将其设置为 `0` 或 `undefined` |
| topLeftCell | special | 哪个单元格将在右下窗格中的左上角。注意:不能是冻结单元格。默认为第一个未冻结的单元格 |
```javascript
worksheet.views = [
{state: 'frozen', xSplit: 2, ySplit: 3, topLeftCell: 'G10', activeCell: 'A1'}
];
```
### 拆分视图[⬆](#目录)<!-- Link generated with jump2header -->
拆分视图支持以下额外属性:
| 属性名 | 默认值 | 描述 |
| ----------------- | --------- | ----------- |
| xSplit | 0 | 从左侧多少个点起,以放置拆分器。要垂直拆分,请将其设置为 `0` 或 `undefined` |
| ySplit | 0 | 从顶部多少个点起,放置拆分器。要水平拆分,请将其设置为 `0` 或 `undefined` |
| topLeftCell | `undefined` | 哪个单元格将在右下窗格中的左上角。 |
| activePane | `undefined` | 哪个窗格将处于活动状态-`topLeft`,`topRight`,`bottomLeft` 和 `bottomRight` 中的一个 |
```javascript
worksheet.views = [
{state: 'split', xSplit: 2000, ySplit: 3000, topLeftCell: 'G10', activeCell: 'A1'}
];
```
## 自动筛选器[⬆](#目录)<!-- Link generated with jump2header -->
可以对工作表应用自动筛选器。
```javascript
worksheet.autoFilter = 'A1:C1';
```
尽管范围字符串是 `autoFilter` 的标准形式,但工作表还将支持以下值:
```javascript
// 将自动筛选器设置为从 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
}
}
```
## 列[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 添加列标题并定义列键和宽度
// 注意:这些列结构仅是构建工作簿的方便之处,除了列宽之外,它们不会完全保留。
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.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);
```
## 行[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 获取一个行对象。如果尚不存在,则将返回一个新的空对象
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[⬆](#contents)<!-- Link generated with jump2header -->
```javascript
// 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'* |
## 处理单个单元格[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
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>';
```
## 合并单元格[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 合并一系列单元格
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[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
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[⬆](#contents)<!-- Link generated with jump2header -->
```javascript
// 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 | |
## 重复行[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
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` |
## 定义名称[⬆](#目录)<!-- Link generated with jump2header -->
单个单元格(或多个单元格组)可以为它们分配名称。名称可用于公式和数据验证(可能还有更多)。
```javascript
// 为单元格分配(或获取)名称(将覆盖该单元具有的其他任何名称)
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']);
```
## 数据验证[⬆](#目录)<!-- Link generated with jump2header -->
单元格可以定义哪些值有效或无效,并提示用户以帮助指导它们。
验证类型可以是以下之一:
| 类型 | 描述 |
| ---------- | ----------- |
| list | 定义一组离散的有效值。Excel 将在下拉菜单中提供这些内容,以便于输入 |
| whole | 该值必须是整数 |
| decimal | 该值必须是十进制数 |
| textLength | 该值可以是文本,但长度是受控的 |
| custom | 自定义公式控制有效值 |
对于 `list` 或 `custom` 以外的其他类型,以下运算符会影响验证:
| 运算符 | 描述 |
| -------------------- | ----------- |
| between | 值必须介于公式结果之间 |
| notBetween | 值不能介于公式结果之间 |
| equal | 值必须等于公式结果 |
| notEqual | 值不能等于公式结果 |
| greaterThan | 值必须大于公式结果 |
| lessThan | 值必须小于公式结果 |
| greaterThanOrEqual | 值必须大于或等于公式结果 |
| lessThanOrEqual | 值必须小于或等于公式结果 |
```javascript
// 指定有效值的列表(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)]
};
```
## 单元格注释[⬆](#目录)<!-- Link generated with jump2header -->
将旧样式的注释添加到单元格
```javascript
// 纯文字笔记
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'
};
```
### 单元格批注属性[⬆](#目录)<!-- Link generated with jump2header -->
下表定义了单元格注释已支持的属性。
| Field | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| texts | Y | | 评论文字 |
| margins | N | {} | 确定自动或自定义设置单元格注释的边距值 |
| protection | N | {} | 可以使用保护属性来指定对象和对象文本的锁定状态 |
| editAs | N | 'absolute' | 可以使用'editAs'属性来指定注释如何锚定到单元格 |
### 单元格批注页边距[⬆](#目录)<!-- Link generated with jump2header -->
确定单元格批注的页面距设置模式,自动或者自定义模式。
```javascript
ws.getCell('B1').note.margins = {
insetmode: 'custom',
inset: [0.25, 0.25, 0.35, 0.35]
}
```
### 已支持的页边距属性[⬆](#目录)<!-- Link generated with jump2header -->
| Property | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| insetmode | N | 'auto' | 确定是否自动设置注释边距,并且值是'auto' 或者 'custom' |
| inset | N | [0.13, 0.13, 0.25, 0.25] | 批注页边距的值,单位是厘米, 方向是左-上-右-下 |
注意:只有当 ```insetmode```的值设置为'custom'时,```inset```的设置才生效。
### 单元格批注保护[⬆](#目录)<!-- Link generated with jump2header -->
可以使用保护属性来修改单元级别保护。
```javascript
ws.getCell('B1').note.protection = {
locked: 'False',
lockText: 'False',
};
```
### 已支持的保护属性[⬆](#目录)<!-- Link generated with jump2header -->
| Property | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| locked | N | 'True' | 此元素指定在保护工作表时对象已锁定 |
| lockText | N | 'True' | 该元素指定对象的文本已锁定 |
### 单元格批注对象位置属性[⬆](#目录)<!-- Link generated with jump2header -->
单元格注释还可以具有属性 'editAs',该属性将控制注释如何锚定到单元格。
它可以具有以下值之一:
```javascript
ws.getCell('B1').note.editAs = 'twoCells'
```
| Value | Description |
| --------- | ----------- |
| twoCells | 它指定注释的大小、位置随单元格而变 |
| oneCells | 它指定注释的大小固定,位置随单元格而变 |
| absolute | 这是默认值,它指定注释的大小、位置均固定 |
## 表格[⬆](#目录)<!-- Link generated with jump2header -->
表允许表格内数据的表内操作。
要将表添加到工作表,请定义表模型并调用 `addTable`:
```javascript
// 将表格添加到工作表
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],
],
});
```
注意:将表格添加到工作表将通过放置表格的标题和行数据来修改工作表。
结果就是表格覆盖的工作表上的所有数据(包括标题和所有的)都将被覆盖。
### 表格属性[⬆](#目录)<!-- Link generated with jump2header -->
下表定义了表格支持的属性。
| 表属性 | 描述 | 是否需要 | 默认值 |
| -------------- | ----------------- | -------- | ------------- |
| name | 表格名称 | Y | |
| displayName | 表格的显示名称 | N | `name` |
| ref | 表格的左上方单元格 | Y | |
| headerRow | 在表格顶部显示标题 | N | true |
| totalsRow | 在表格底部显示总计 | N | `false` |
| style | 额外的样式属性 | N | {} |
| columns | 列定义 | Y | |
| rows | 数据行 | Y | |
### 表格样式属性[⬆](#目录)<!-- Link generated with jump2header -->
下表定义了表格中支持的属性样式属性。
| 样式属性 | 描述 | 是否需要 | 默认值 |
| ------------------ | ----------------- | -------- | ------------- |
| theme | 桌子的颜色主题 | N | `'TableStyleMedium2'` |
| showFirstColumn | 突出显示第一列(粗体) | N | `false` |
| showLastColumn | 突出显示最后一列(粗体) | N | `false` |
| showRowStripes | 用交替的背景色显示行 | N | `false` |
| showColumnStripes | 用交替的背景色显示列 | N | `false` |
### 表格列属性[⬆](#目录)<!-- Link generated with jump2header -->
下表定义了每个表格列中支持的属性。
| 列属性 | 描述 | 是否需要 | 默认值 |
| ------------------ | ----------------- | -------- | ------------- |
| name | 列名,也用在标题中 | Y | |
| filterButton | 切换标题中的过滤器控件 | N | false |
| totalsRowLabel | 用于描述统计行的标签(第一列) | N | `'Total'` |
| totalsRowFunction | 统计函数名称 | N | `'none'` |
| totalsRowFormula | 自定义函数的可选公式 | N | |
### 统计函数[⬆](#目录)<!-- Link generated with jump2header -->
下表列出了由列定义的 `totalsRowFunction` 属性的有效值。如果使用 `'custom'` 以外的任何值,则无需包括关联的公式,因为该公式将被表格插入。
| 统计函数 | 描述 |
| ------------------ | ----------------- |
| none | 此列没有统计函数 |
| average | 计算列的平均值 |
| countNums | 统计数字条目数 |
| count | 条目数 |
| max | 此列中的最大值 |
| min | 此列中的最小值 |
| stdDev | 该列的标准偏差 |
| var | 此列的方差 |
| sum | 此列的条目总数 |
| custom | 自定义公式。 需要关联的 `totalsRowFormula` 值。 |
### 表格样式主题[⬆](#目录)<!-- Link generated with jump2header -->
有效的主题名称遵循以下模式:
* "TableStyle[Shade][Number]"
Shades(阴影),Number(数字)可以是以下之一:
* Light, 1-21
* Medium, 1-28
* Dark, 1-11
对于无主题,请使用值 `null`。
注意:exceljs 尚不支持自定义表格主题。
### 修改表格[⬆](#目录)<!-- Link generated with jump2header -->
表格支持一组操作函数,这些操作函数允许添加或删除数据以及更改某些属性。由于这些操作中的许多操作可能会对工作表产生副作用,因此更改必须在完成后立即提交。
表中的所有索引值均基于零,因此第一行号和第一列号为 `0`。
**添加或删除标题和统计**
```javascript
const table = ws.getTable('MyTable');
// 打开标题行
table.headerRow = true;
// 关闭统计行
table.totalsRow = false;
// 将表更改提交到工作表中
table.commit();
```
**重定位表**
```javascript
const table = ws.getTable('MyTable');
// 表格左上移至 D4
table.ref = 'D4';
// 将表更改提交到工作表中
table.commit();
```
**添加和删除行**
```javascript
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();
```
**添加和删除列**
```javascript
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();
```
**更改列属性**
```javascript
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();
```
## 样式[⬆](#目录)<!-- Link generated with jump2header -->
单元格,行和列均支持一组丰富的样式和格式,这些样式和格式会影响单元格的显示方式。
通过分配以下属性来设置样式:
* <a href="#数字格式">numFmt</a>
* <a href="#字体">font</a>
* <a href="#对齐">alignment</a>
* <a href="#边框">border</a>
* <a href="#填充">fill</a>
```javascript
// 为单元格分配样式
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.numFmt` 和 `row.font`),则单元格将继承行的字体和列的 `numFmt`。
注意:以上所有属性(`numFmt`(字符串)除外)都是 JS 对象结构。如果将同一样式对象分配给多个电子表格实体,则每个实体将共享同一样式对象。如果样式对象后来在电子表格序列化之前被修改,则所有引用该样式对象的实体也将被修改。此行为旨在通过减少创建的JS对象的数量来优先考虑性能。如果希望样式对象是独立的,则需要先对其进行克隆,然后再分配它们。同样,默认情况下,如果电子表格实体共享相似的样式,则从文件(或流)中读取文档时,它们也将引用相同的样式对象。
### 数字格式[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 将值显示为“ 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%';
```
### 字体
```javascript
// 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 | 字体 <u>下划线</u> 样式 | true, false, 'none', 'single', 'double', 'singleAccounting', 'doubleAccounting' |
| strike | 字体 <strike>删除线</strike> | true, false |
| outline | 字体轮廓 | true, false |
| vertAlign | 垂直对齐 | 'superscript', 'subscript'
### 对齐[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 将单元格对齐方式设置为左上,中间居中,右下
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 | | | | | | |
### 边框[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 在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
### 填充[⬆](#目录)<!-- Link generated with jump2header -->
```javascript
// 用红色深色垂直条纹填充A1
ws.getCell('A1').fill = {
t