动态数组简介

动态数组是 SpreadJS 的重要计算特性,允许公式自动将多个结果溢出到相邻单元格,替代传统的数组公式。当公式返回多个值时,结果会自动填充到相邻的空白单元格区域,无需手动复制公式。

动态数组特别适用于数据处理和分析场景,如生成序列数字、筛选数据、提取唯一值和排序等操作。通过动态数组函数(如 SEQUENCE、FILTER、UNIQUE、SORT 等),用户可以更高效地处理表格数据,减少重复性的公式操作。

概述 本 Demo 展示了动态数组的基本概念和溢出行为。通过 SEQUENCE 函数演示了动态数组如何自动将结果溢出到相邻单元格,以及当溢出区域被阻挡时如何显示 #SPILL! 错误。 实现思路 初始化 Workbook 并启用动态数组功能 挂起绘制和计算服务以提升性能 设置两个 SEQUENCE 公式示例: 第一个公式在 C3 单元格,结果可以正常溢出到相邻 9 个单元格(3x3) 第二个公式在 C9 单元格,但 D10 单元格被占用,导致溢出受阻 绑定复选框事件,允许用户切换动态数组功能的开关 恢复计算和绘制服务 代码解析 启用动态数组功能 动态数组功能需要显式启用。可以在创建 Workbook 时传入配置,也可以通过 spread.options.allowDynamicArray 属性设置。 设置 SEQUENCE 公式 SEQUENCE 函数生成一个 3 行 3 列的数字序列(1-9)。公式设置在 C3 单元格(第 2 行第 2 列,索引从 0 开始),结果会自动溢出到 D3:E5 区域。 模拟溢出错误场景 在第二个示例中,SEQUENCE 函数本应溢出到 D10:F12 区域,但 D10 单元格(第 9 行第 3 列)已被设置值为 3,导致公式无法溢出,显示 #SPILL! 错误。 动态切换功能 通过复选框可以动态启用或禁用动态数组功能。切换后会触发重新计算,让用户直观看到功能开关对公式结果的影响。 运行效果 表格上方区域显示一个 3x3 的数字序列(1-9),这是 SEQUENCE(3,3) 的溢出结果 表格下方区域显示 #SPILL! 错误,因为该公式的溢出区域被已占用的单元格阻挡 取消勾选"允许动态数组"复选框后,公式将不再自动溢出,需要手动处理数组结果 重新勾选复选框,动态数组功能恢复,公式重新计算并溢出 API 参考 allowDynamicArray 属性 类型:boolean 默认值:false 说明:控制是否启用动态数组功能,必须在创建 Workbook 后设置或通过构造函数配置传入 SEQUENCE 函数 rows:必需,返回数组的行数 [columns]:可选,返回数组的列数,默认为 1 [start]:可选,序列的起始值,默认为 1 [step]:可选,序列的递增值,默认为 1 SEQUENCE 函数仅在 allowDynamicArray 为 true 时有效,返回的数组会自动溢出到相邻单元格。 recalcAll 方法 force:是否强制重新计算所有公式 说明:触发工作表的重新计算,用于动态数组功能切换后更新公式结果
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(_getElementById("ss")); initSpread(spread); }; function initSpread(spread) { spread.options.allowDynamicArray = true; var sheet = spread.getActiveSheet(); spread.suspendPaint(); spread.suspendCalcService(); sheet.setValue(1, 2, "=SEQUENCE(3,3)"); sheet.setFormula(2, 2, 'SEQUENCE(3,3)'); sheet.setValue(7, 2, "=SEQUENCE(3,3)"); sheet.setFormula(8, 2, 'SEQUENCE(3,3)'); sheet.setValue(9, 3, 3); bindEvent(spread, sheet); spread.resumeCalcService(); spread.resumePaint(); } function bindEvent (spread, sheet) { _getElementById("allowDynamicArray").addEventListener('change', function () { spread.options.allowDynamicArray = this.checked; sheet && sheet.recalcAll(true); }); } function _getElementById(id) { return document.getElementById(id); }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta name="spreadjs culture" content="zh-cn" /> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-resources-zh/dist/gc.spread.sheets.resources.zh.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"></div> <div class="options-container"> <div class="option-row"> <input style="width: 20px;float: left;" type="checkbox" id="allowDynamicArray" checked="checked" /> <label for="allowDynamicArray">允许动态数组</label> </div> </div> </div> </body> </html>
.sample { position: relative; height: 100%; overflow: auto; } .sample::after { display: block; content: ""; clear: both; } .sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 10px; } .option-group { margin-bottom: 6px; } label { display: block; margin-bottom: 6px; } input { margin-bottom: 5px; padding: 2px 4px; width: 100%; box-sizing: border-box; } input[type=button] { margin-bottom: 6px; } hr { border-color: #fff; opacity: .2; margin: 5px 0; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }