# ohos_exceljs **Repository Path**: baofengworkspace/ohos_exceljs ## Basic Information - **Project Name**: ohos_exceljs - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-03-27 - **Last Updated**: 2025-06-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ExcelJS ## 简介 ExcelJS是一个用于读取,操作并写入电子表格数据和样式到XLSX文件的工具库。本库基于ExcelJS 原库 v4.4.0 版本进行适配,使其可以运行在 OpenHarmony,并沿用其现有用法和特性。 ## 下载安装 ```javascript ohpm install @ohos/exceljs ``` OpenHarmony ohpm 环境配置等更多内容,请参考[如何安装 OpenHarmony ohpm 包](https://gitee.com/openharmony-tpc/docs/blob/master/OpenHarmony_har_usage.md) ## 接口和属性列表 接口列表 **Workbook** | **接口** | 参数 | 功能 | | ------------------------------------------------------------ | --------------------------------------- | ------------------------ | | addWorksheet(name?: string, options?: Partial): Worksheet; | name:工作表名称
options:配置参数 | 添加工作表 | | removeWorksheet(indexOrName: number\|string):void | indexOrName:工作表名称或者索引 | 删除工作表 | | getWorksheet(indexOrName?: number \|string): Worksheet \|undefined | indexOrName:工作表名称或者索引 | 按名称或id获取工作表 | | eachSheet(callback: (worksheet: Worksheet, id: number) => void): void; | callback:遍历工作表回调函数 | 遍历所有工作表 | | clearThemes(): void | | 清除主题 | | addImage(img: Image): number | img:图片支持base64,buffer和路径 | 将图像添加到工作簿并返回id | | getImage(id: number): Image | id:工作薄中图片对应的ID | 按id获取图像 | **Worksheet** | **接口** | 参数 | 功能 | | ------------------------------------------------------------ | ------------------------------------------------------------ |----------------------------------------------| | getColumnKey(key: string): Column | key:列对应的key | 按key获取列 | | setColumnKey(key: string, value: Column): void | key:列对应的key
value:设置的列 | 设置工作表中列的key | | deleteColumnKey(key: string): void | key:列对应的key | 删除工作表中列的key | | eachColumnKey(callback: (col: Column, index: number) => void): void | callback:遍历工作表回调函数 | 按key遍历工作表所有列 | | getColumn(indexOrKey: number \|string): Column | indexOrKey:列的key或者索引 | 按key或者index获取单个列 | | spliceColumns(start: number, count: number, ...insert: any[][]): void | start:起始索引位置
count:插入列数
insert:插入列 | 拼接列 | | findRow(row: number): Row \|undefined | row:行号 | 按行号查找单行,不存在返回undefined | | findRows(start: number, length: number): Row[] \|undefined | start:起始行号
length:行数 | 按行号查找多行,不存在返回undefined | | spliceRows(start: number, count: number, ...insert: any[][]): void | start:起始索引位置
count:插入行数
insert:插入行 | 拼接行 | | addRow(data: any[] \|any, style?: string): Row | data:行数据
style:行样式 | 在最后一行后按键值添加一行 | | addRows(rows: any[], style?: string): Row[] | rows:行数据
style:行样式 | 在最后一行后按键值添加多行 | | insertRow(pos: number, value: any[] \|any, style?: string): Row | pos:插入位置
value:插入行数据 | 插入单行 | | insertRows(pos: number, values: any[], style?: string): Row[] | pos:插入位置
value:插入行数据 | 插入多行 | | duplicateRow(rowNum: number, count: number, insert: boolean): void | rowNum:行索引
count:行数
insert:是否插入 | 复制行并插入新行 | | getRow(index: number): Row | index:行索引 | 按从1开始的索引获取或创建行 | | getRows(start: number, length: number): Row[] \|undefined | start:起始位置
length:长度 | 按从1开始的索引获取或创建多行 | | eachRow(callback: (row: Row, rowNumber: number) => void): void | callback:遍历行回调函数 | 遍历工作表中所有有值的行 | | eachRow(opt: { includeEmpty: boolean }, callback: (row: Row, rowNumber: number) => void): void | opt:是否包含空行
callback:遍历行回调函数 | 遍历工作表中的所有行(包括空行) | | getSheetValues(): RowValues[] | | 将所有行作为稀疏数组返回 | | findCell(r: number \|string, c: number \|string): Cell \|undefined | r:行名称或索引
c:列名称或索引 | 查找单元格 | | getCell(r: number \|string, c?: number \|string): Cell | r:行名称或索引
c:列名称或索引 | 获取或创建单元格 | | mergeCells(v: string): void | v:单元格行和列,如:'A1:B1' | 合并单元格 | | mergeCells(top: number, left: number, bottom: number, right: number, sheetName?: string): void | top:最上位置索引
left:最左位置索引
bottom:最下位置索引
right:最右位置索引
sheetName:工作表名称 | 合并单元格 | | mergeCellsWithoutStyle(v: string): void | v:单元格行和列,如:'A1:B1' | 合并单元格 | | mergeCellsWithoutStyle(top: number, left: number, bottom: number, right: number, sheetName?: string): void | top:最上位置索引
left:最左位置索引
bottom:最下位置索引
right:最右位置索引
sheetName:工作表名称 | 合并单元格不合并样式 | | unMergeCells(v: string): void | v:单元格行和列,如:'A1:B1' | 取消合并单元格 | | fillFormula(range: Range \|string \|Location, formula: string, results?: ((r: number, c: number) => string \|number) \|number[] \|number[][]): void | range:填充范围
formula:填充公式
results:填充结果回调函数 | 填充公式 | | addBackgroundImage(imageId: number): void | imageId:Workbook中图片id | 使用“Workbook.addImage”中的图片id,设置工作表的背景 | | getBackgroundImageId(): string | | 获取背景图片的id | | addImage(imageId: number, range: string \|{ editAs?: string; } & ImageRange & { hyperlinks?: ImageHyperlinkValue } \|{ editAs?: string; } & ImagePosition & { hyperlinks?: ImageHyperlinkValue }): void | imageId:图片ID
range:覆盖范围
| 使用“Workbook.addImage”中的图像id,在工作表中嵌入图像以覆盖一个范围 | | getImages(): Array<{type: 'image',imageId: string; range: ImageRange;}> | | 获取图片 | | protect(password: string, options: Partial): Promise | password:密码
options:配置项 | 设置工作表保护 | | unprotect(): void | | 解除工作表保护 | | addTable(tableProperties: TableProperties): Table | tableProperties:表格属性 | 添加一个新表并返回对它的引用 | | getTable(name: string): Table | name:表名 | 获取表格 | | removeTable(name: string): void | name:表名 | 删除表格 | | getTables(): \[Table, void\]\[\] | | 获取所有表格 | | addConditionalFormatting(cf: ConditionalFormattingOptions): void | cf:条件化参数 | 添加条件格式化选项 | | removeConditionalFormatting(filter: any): void | filter:过滤条件 | 删除条件格式化选项 | **Row** | **接口** | 参数 | 功能 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------- | | getCell(indexOrKey: number \|string): Cell | indexOrKey:列的key或索引 | 按数字、列字母或列键获取单元格 | | findCell(colNumber: number): Cell \|undefined | colNumber:列的索引 | 按列索引查找单元格 | | getWorksheet(indexOrName?: number \|string): Worksheet \|undefined | indexOrName:工作表名称或者索引 | 发送按名称或id获取工作表 | | eachCell(callback: (cell: Cell, colNumber: number) => void): void | callback:遍历单元格回调函数 | 遍历一行所有非空单元格 | | eachCell(opt: { includeEmpty: boolean }, callback: (cell: Cell, colNumber: number) => void): void | opt:配置项
callback:遍历单元格回调函数 | 遍历一行所有单元格(包括空单元格) | | splice(start: number, count: number, ...insert: any[]): void | start:起始索引
count:单元格数量
insert:插入的单元格 | 插入单元 | **Column** | **接口** | 参数 | 功能 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------- | | eachCell(callback: (cell: Cell, rowNumber: number) => void): void | callback:遍历单元格回调函数 | 迭代此列中的所有当前单元格 | | eachCell(opt: { includeEmpty: boolean }, callback: (cell: Cell, rowNumber: number) => void): void | colNumber:列的索引 | 按列索引查找单元格 | **cell** | **接口** | 参数 | 功能 | | ------------------------------------------------ | ----------------------------------------------- | -------------------- | | addName(name: string): void | name:名称 | 单元格添加名称 | | removeName(name: string): void | name:名称 | 移除单元格名称 | | removeAllNames(): void | | 移除所有单元格名称 | | merge(master: Cell, ignoreStyle?: boolean): void | master:主单元格
ignoreStyle:是否忽略样式 | 合并单元格到主单元格 | | unmerge(): void | | 取消合并单元格 | **table** | **接口** | 参数 | 功能 | | ------------------------------------------------------------ | ---------------------------------------- | ----------------------------------------- | | addRow: (values: any[], rowNumber?: number) => void | values:行数据
rowNumber:行号 | 添加一行数据,可以在rowNumber处插入或追加 | | removeRows: (rowIndex: number, count: number) => void | rowIndex:行索引
count:行数 | 删除行数据 | | getColumn: (colIndex: number) => TableColumn | | 获取表格列 | | addColumn: (column: TableColumnProperties, values: any[], colIndex: number) => void | column:表格列属性
colIndex:列索引 | 添加一个新列,包括列的定义和值 | | removeColumns: (colIndex: number, count: number) => void | colIndex:列索引
count:列的数量 | 删除列数据 | ## 使用示例 ### 创建工作簿 ```javascript import ExcelJS from '@ohos/exceljs' const workbook = new ExcelJS.Workbook(); ``` ### 设置工作簿属性 ```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 workbook.properties.date1904 = true; ``` ### 设置计算属性 ```javascript // 在加载时强制工作簿计算属性 workbook.calcProperties.fullCalcOnLoad = true; ``` ### 工作簿视图 工作簿视图控制在查看工作簿时 Excel 将打开多少个单独的窗口。 ```javascript workbook.views = [ { x: 0, y: 0, width: 10000, height: 20000, firstSheet: 0, activeTab: 1, visibility: 'visible' } ] ``` ### 添加工作表 ```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}]}); ``` ### 删除工作表 使用工作表的 `id` 从工作簿中删除工作表。 示例: ```javascript // 创建工作表 const sheet = workbook.addWorksheet('My Sheet'); // 使用工作表 id 删除工作表 workbook.removeWorksheet(sheet.id) ``` ### 访问工作表 ```javascript // 遍历所有工作表 // 注意: workbook.worksheets.forEach 仍然是可以正常运行的, 但是以下的方式更好 workbook.eachSheet(function(worksheet, sheetId) { // ... }); // 按 name 提取工作表 const worksheet = workbook.getWorksheet('My Sheet'); // 按 id 提取工作表 const worksheet = workbook.getWorksheet(1); ``` ### 工作表状态 ```javascript // 使工作表可见 worksheet.state = 'visible'; // 隐藏工作表 worksheet.state = 'hidden'; // 从“隐藏/取消隐藏”对话框中隐藏工作表 worksheet.state = 'veryHidden'; ``` ### 工作表属性 工作表支持属性存储,以允许控制工作表的某些功能。 ```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 | ### 工作表尺寸 一些新的尺寸属性已添加到工作表中... | 属性名 | 描述 | | ----------------- | ------------------------------------------------------------ | | rowCount | 文档的总行数。 等于具有值的最后一行的行号。 | | actualRowCount | 具有值的行数的计数。 如果中间文档行为空,则该行将不包括在计数中。 | | columnCount | 文档的总列数。 等于所有行的最大单元数。 | | actualColumnCount | 具有值的列数的计数。 | ### 页面设置 所有可能影响工作表打印的属性都保存在工作表上的 `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 | ### 页眉和页脚 这是添加页眉和页脚的方法。 添加的内容主要是文本,例如时间,简介,文件信息等,您可以设置文本的样式。 此外,您可以为首页和偶数页设置不同的文本。 注意:目前不支持图片。 ```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 | ### 工作表视图 现在,工作表支持视图列表,这些视图控制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` 视图不兼容 | #### 冻结视图 冻结视图支持以下额外属性: | 属性名 | 默认值 | 描述 | | ----------------- | --------- | ----------- | | xSplit | 0 | 冻结多少列。要仅冻结行,请将其设置为 `0` 或 `undefined` | | ySplit | 0 | 冻结多少行。要仅冻结列,请将其设置为 `0` 或 `undefined` | | topLeftCell | special | 哪个单元格将在右下窗格中的左上角。注意:不能是冻结单元格。默认为第一个未冻结的单元格 | ```javascript worksheet.views = [ {state: 'frozen', xSplit: 2, ySplit: 3, topLeftCell: 'G10', activeCell: 'A1'} ]; ``` #### 拆分视图 拆分视图支持以下额外属性: | 属性名 | 默认值 | 描述 | | ----------------- | --------- | ----------- | | 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'} ]; ``` ### 自动筛选器 可以对工作表应用自动筛选器。 ```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 } } ``` ### 列 ```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); ``` ### 行 ```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 ```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'* | ### 处理单个单元格 ```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 = '
' + cell.html + '
'; ``` ### 合并单元格 ```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 ```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 ```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 | | ### 重复行 ```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` | ### 定义名称 单个单元格(或多个单元格组)可以为它们分配名称。名称可用于公式和数据验证(可能还有更多)。 ```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']); ``` ### 数据验证 单元格可以定义哪些值有效或无效,并提示用户以帮助指导它们。 验证类型可以是以下之一: | 类型 | 描述 | | ---------- | ----------- | | 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)] }; ``` ### 单元格注释 将旧样式的注释添加到单元格 ```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' }; ``` #### 单元格批注属性 下表定义了单元格注释已支持的属性。 | Field | Required | Default Value | Description | | -------- | -------- | ------------- | ----------- | | texts | Y | | 评论文字 | | margins | N | {} | 确定自动或自定义设置单元格注释的边距值 | | protection | N | {} | 可以使用保护属性来指定对象和对象文本的锁定状态 | | editAs | N | 'absolute' | 可以使用'editAs'属性来指定注释如何锚定到单元格 | #### 单元格批注页边距 确定单元格批注的页面距设置模式,自动或者自定义模式。 ```javascript 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```的设置才生效。 #### 单元格批注保护 可以使用保护属性来修改单元级别保护。 ```javascript ws.getCell('B1').note.protection = { locked: 'False', lockText: 'False', }; ``` #### 已支持的保护属性 | Property | Required | Default Value | Description | | -------- | -------- | ------------- | ----------- | | locked | N | 'True' | 此元素指定在保护工作表时对象已锁定 | | lockText | N | 'True' | 该元素指定对象的文本已锁定 | #### 单元格批注对象位置属性 单元格注释还可以具有属性 'editAs',该属性将控制注释如何锚定到单元格。 它可以具有以下值之一: ```javascript ws.getCell('B1').note.editAs = 'twoCells' ``` | Value | Description | | --------- | ----------- | | twoCells | 它指定注释的大小、位置随单元格而变 | | oneCells | 它指定注释的大小固定,位置随单元格而变 | | absolute | 这是默认值,它指定注释的大小、位置均固定 | ### 表格 表允许表格内数据的表内操作。 要将表添加到工作表,请定义表模型并调用 `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], ], }); ``` 注意:将表格添加到工作表将通过放置表格的标题和行数据来修改工作表。 结果就是表格覆盖的工作表上的所有数据(包括标题和所有的)都将被覆盖。 #### 表格属性 下表定义了表格支持的属性。 | 表属性 | 描述 | 是否需要 | 默认值 | | -------------- | ----------------- | -------- | ------------- | | 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`。 **添加或删除标题和统计** ```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(); ``` ### 样式 单元格,行和列均支持一组丰富的样式和格式,这些样式和格式会影响单元格的显示方式。 通过分配以下属性来设置样式: * numFmt * font * alignment * border * fill ```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对象的数量来优先考虑性能。如果希望样式对象是独立的,则需要先对其进行克隆,然后再分配它们。同样,默认情况下,如果电子表格实体共享相似的样式,则从文件(或流)中读取文档时,它们也将引用相同的样式对象。 #### 数字格式 ```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 | 字体 下划线 样式 | true, false, 'none', 'single', 'double', 'singleAccounting', 'doubleAccounting' | | strike | 字体 删除线 | true, false | | outline | 字体轮廓 | true, false | | vertAlign | 垂直对齐 | 'superscript', 'subscript' #### 对齐 ```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 | | | | | | | #### 边框 ```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 #### 填充 ```javascript // 用红色深色垂直条纹填充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文本或单元格格式化。富文本值可以控制文本值内任意数量的子字符串的字体属性。有关支持哪些字体属性的详细信息,请参见字体。 ```javascript 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); ``` #### 单元格保护 可以使用保护属性来修改单元级别保护。 ```javascript ws.getCell('A1').protection = { locked: false, hidden: true, }; ``` **支持的保护属性** | 属性 | 默认值 | 描述 | | -------- | ------- | ----------- | | locked | `true` | 指定在工作表受保护的情况下是否将单元格锁定。 | | hidden | `false` | 指定如果工作表受保护,则单元格的公式是否可见。 | ### 条件格式化 条件格式化允许工作表根据单元格值或任意公式显示特定的样式,图标等。 条件格式设置规则是在工作表级别添加的,通常会覆盖一系列单元格。 可以将多个规则应用于给定的单元格范围,并且每个规则都将应用自己的样式。 如果多个规则影响给定的单元格,则规则优先级值将确定如果竞争样式冲突,则哪个规则胜出。优先级值较低的规则获胜。如果没有为给定规则指定优先级值,ExcelJS 将按升序分配它们。 注意:目前,仅支持条件格式设置规则的子集。具体来说,只有格式规则不需要 <extLst> 元素内的 XML 呈现。这意味着不支持数据集和三个特定的图标集(3Triangles,3Stars,5Boxes)。 ```javascript // 根据行和列为偶数或奇数向 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 支持大纲;行或列可以根据用户希望查看的详细程度展开或折叠。 大纲级别可以在列设置中定义: ```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 } ]; ``` 或直接在行或列上 ```javascript worksheet.getColumn(3).outlineLevel = 1; worksheet.getRow(3).outlineLevel = 1; ``` 工作表大纲级别可以在工作表上设置 ```javascript // 设置列大纲级别 worksheet.properties.outlineLevelCol = 1; // 设置行大纲级别 worksheet.properties.outlineLevelRow = 1; ``` 注意:调整行或列上的大纲级别或工作表上的大纲级别将产生副作用,即还修改受属性更改影响的所有行或列的折叠属性。 例如。: ```javascript 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; ``` 大纲属性可以在工作表上设置 ```javascript worksheet.properties.outlineProperties = { summaryBelow: false, summaryRight: false, }; ``` ### 图片 将图像添加到工作表是一个分为两个步骤的过程。首先,通过 `addImage()` 函数将图像添加到工作簿中,该函数还将返回 `imageId` 值。然后,使用 `imageId`,可以将图像作为平铺背景或覆盖单元格区域添加到工作表中。 注意:从此版本开始,不支持调整或变换图像。 #### 将图片添加到工作簿 `Workbook.addImage` 函数支持按文件名或按 `Buffer` 添加图像。请注意,在两种情况下,都必须指定扩展名。有效的扩展名包括 “jpeg”,“png”,“gif”。 ```javascript // 通过文件名将图像添加到工作簿 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` 函数设置工作表的背景 ```javascript // 设置背景 worksheet.addBackgroundImage(imageId1); ``` #### 在一定范围内添加图片 使用 `Workbook.addImage` 中的图像 `ID`,可以将图像嵌入工作表中以覆盖一定范围。从该范围计算出的坐标将覆盖从第一个单元格的左上角到第二个单元格的右下角。 ```javascript // 在 B2:D6 上插入图片 worksheet.addImage(imageId2, 'B2:D6'); ``` 使用结构而不是范围字符串,可以部分覆盖单元格。 请注意,为此使用的坐标系基于零,因此 A1 的左上角将为 `{col:0,row:0}`。单元格的分数可以通过使用浮点数来指定,例如 A1 的中点是 `{col:0.5,row:0.5}`。 ```javascript // 在 B2:D6 的一部分上插入图像 worksheet.addImage(imageId2, { tl: { col: 1.5, row: 1.5 }, br: { col: 3.5, row: 5.5 } }); ``` 单元格区域还可以具有属性 `"editAs"`,该属性将控制将图像锚定到单元格的方式。它可以具有以下值之一: | 值 | 描述 | | --------- | ----------- | | `undefined` | 它指定使图像将根据单元格移动和调整其大小 | | `oneCell` | 这是默认值。图像将与单元格一起移动,但大小不变动 | | `absolute` | 图像将不会随着单元格移动或调整大小 | ```javascript ws.addImage(imageId, { tl: { col: 0.1125, row: 0.4 }, br: { col: 2.101046875, row: 3.4 }, editAs: 'oneCell' }); ``` #### 将图片添加到单元格 您可以将图像添加到单元格,然后以 96dpi 定义其宽度和高度(以像素为单位)。 ```javascript worksheet.addImage(imageId2, { tl: { col: 0, row: 0 }, ext: { width: 500, height: 200 } }); ``` #### 添加带有超链接的图片 您可以将带有超链接的图像添加到单元格,并在图像范围内定义超链接。 ```javascript worksheet.addImage(imageId2, { tl: { col: 0, row: 0 }, ext: { width: 500, height: 200 }, hyperlinks: { hyperlink: 'http://www.somewhere.com', tooltip: 'http://www.somewhere.com' } }); ``` #### 工作表保护 可以通过添加密码来保护工作表免受修改。 ```javascript await worksheet.protect('the-password', options); ``` 工作表保护也可以删除: ```javascript 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 | 保护或取消保护时执行的哈希迭代次数 | #### XLSX ##### 读 XLSX ```javascript // 从文件读取 const workbook = new Excel.Workbook(); await workbook.xlsx.readFile(filename); ``` ##### 写 XLSX ```javascript // 写入文件 const workbook = createAndFillWorkbook(); await workbook.xlsx.writeFile(filename); ``` ## 约束与限制 在下述版本验证通过: DevEco Studio: DevEco Studio 5.0.2 Release(5.0.7.210, SDK: API14(5.0.2.123) ## 目录结构 ```javascript |---- exceljs | |---- AppScope # 示例代码文件夹 | |---- entry # 示例代码文件夹 | |---- library # exceljs库文件夹 | |---- src/main/ets/lib # 核心代码 | |---- doc # 功能实现 | |---- xlsx # xlsx解析,转换xml核心代码 | |---- utils # 工具方法 | |---- excel.js # 入口文件 | |---- index.d.ts # 声明文件 | |---- README.md # 安装使用方法 | |---- README_zh.md # 安装使用方法 | |---- README.OpenSource # 开源说明 | |---- CHANGELOG.md # 更新日志 ``` ## 贡献代码 使用过程中发现任何问题都可以提交[Issue](https://gitee.com/openharmony-sig/exceljs/issues),当然,也非常欢迎提交[PR](https://gitee.com/openharmony-sig/exceljs/pulls) 。 ## 开源协议 本项目遵循 [MIT License](https://gitee.com/openharmony-sig/exceljs/blob/master/LICENSE)。