隐式交集运算符 @

隐式交集运算符 @ 用于将范围引用转换为单个值。当公式引用的范围跨越多个单元格时,该运算符会根据隐式交集逻辑返回公式所在行或列的交集值,适用于需要在动态数组环境中兼容传统公式的场景。

概述 本 Demo 展示了隐式交集运算符 @ 的工作原理和使用场景。通过生成项目编号序列并设置不同的引用范围,演示了 @ 运算符在正常交集、无交集和多重交集三种情况下的行为,帮助用户理解如何在动态数组环境中处理传统的单值公式。 实现思路 启用动态数组功能(allowDynamicArray = true) 创建表格结构,使用 SEQUENCE 函数生成 1-10 的项目编号 演示 @ 运算符的三种使用情况: 正常交集:公式单元格与引用范围在同一行 错误情况一:公式单元格与引用范围没有交集 错误情况二:公式单元格与引用范围有多个交集 代码解析 启用动态数组 启用动态数组功能是使用 @ 运算符的前提条件。SpreadJS 需要显式设置 allowDynamicArray 为 true 才能支持动态数组相关功能。 生成项目编号 使用 SEQUENCE 函数生成 1-10 的连续数字作为项目编号。SEQUENCE(10) 返回一个包含 10 行 1 列的数组,值从 1 到 10。SEQUENCE 函数的语法为: rows:必需,要返回数据的行数 columns:可选,要返回数据的列数,默认为 1 start:可选,序列的第一个数字,默认为 1 step:可选,序列中的递增值,默认为 1 演示 @ 运算符行为 这段代码为右侧列的每一行设置相同的公式 @$B$9:$B$18。@ 运算符会自动根据公式所在的行,从范围中返回对应行的值。例如第 8 行的公式返回 B9 的值(1),第 9 行返回 B10 的值(2),以此类推。 隐式交集运算符 @ 的工作逻辑如下: 如果值是单个项,则返回该项 如果值是一个区域,则从与公式位于同一行或列的单元格中返回值 如果值是数组,则选择左上角的值 错误示例 第一个错误示例:第 20 行的公式与范围 B9:B18 没有交集(行号不在范围内),返回 #VALUE! 错误。 第二个错误示例:E9 单元格的公式引用范围 B10:D10 与公式单元格同行但有三个单元格(B10、C10、D10),无法确定返回哪个值,返回 #VALUE! 错误。 运行效果 表格左侧列(B 列)显示项目编号 1-10,使用 SEQUENCE 函数自动生成 表格右侧列(D 列)显示 @ 运算符处理后的值,每一行自动返回对应行的编号: D9 单元格返回 B9 的值(1) D10 单元格返回 B10 的值(2) 以此类推,D18 单元格返回 B18 的值(10) 第 21 行显示 #VALUE! 错误,并标注
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.name('@'); sheet.setText(0, 1, '隐式交集运算符 @ 使用隐式交集计算表达式。该公式可以返回一个值、范围或错误。'); sheet.setText(1, 1, '当值为一个范围时,@ 将返回公式单元格所在行和列交叉处的值。'); sheet.setText(2, 1, ' 语法: @值'); var row = 7; var col = 1; var col2 = col + 2; var rowCount = 11; applyTableStyleForRange(sheet, row, col, rowCount, 1); applyTableStyleForRange(sheet, row, col2, rowCount, 1); sheet.getCell(row, col).text('项目编号').hAlign(2); sheet.getCell(row, col2).text('@').hAlign(2); row++; sheet.setFormula(row, col, 'SEQUENCE(10)'); for(var i = 0, r = row; i < 10; i++, r++) { sheet.setFormula(r, col2, '@$B$9:$B$18'); } sheet.setFormula(20, col2, '@$B$9:$B$18'); sheet.setText(20, col2 + 1, ' <--- 错误:没有交集'); sheet.setFormula(9, col2 + 2, '@$B$10:$D$10'); sheet.setText(9, col2 + 3, ' <--- 错误:与多个单元格相交'); spread.resumeCalcService(); spread.resumePaint(); } function applyTableStyleForRange(sheet, row, col, rowCount, colCount, options) { var tableName = "tmpTable"; var TableThemes = GC.Spread.Sheets.Tables.TableThemes; // use table to help set style then remove like convert table to range in Excel sheet.tables.add(tableName, row, col, rowCount, colCount, TableThemes.medium7, options); sheet.tables.remove(tableName, 2 /* keep style */); } 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" style="width:100%; height: 100%"></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; }