扩展上下文菜单

SpreadJS 支持通过 menuData 动态添加或移除自定义上下文菜单项,允许开发者为表格应用添加个性化的右键菜单功能。本 Demo 演示了如何通过操作 menuData 数组来管理上下文菜单项,支持通过命令字符串或直接使用函数两种方式定义菜单行为,并可指定菜单项在特定区域(如 viewport、rowHeader 等)的显示范围。

概述 本 Demo 展示了如何扩展 SpreadJS 的上下文菜单,通过操作 spread.contextMenu.menuData 数组动态添加或移除自定义菜单项。Demo 中演示了两个自定义菜单项:"设置单元格格式"(通过注册命令字符串实现)和"打开对话框"(通过函数直接实现),并提供了复选框来控制菜单项的添加和移除。 实现思路 通过复选框的 onchange 事件控制菜单项的添加和移除 添加菜单项前,先遍历 menuData 检查是否已存在,避免重复添加 使用 menuData.push() 添加新菜单项,使用 menuData.splice() 移除菜单项 对于"设置单元格格式"菜单项:注册命令字符串到 commandManager,然后实现命令的 execute 方法 对于"打开对话框"菜单项:直接将函数作为 command 属性值 代码解析 添加菜单项并注册命令 这段代码展示了如何通过命令字符串的方式添加菜单项。首先定义菜单项配置,其中 command 属性使用字符串标识符。然后通过 commandManager().register() 注册该命令的具体实现逻辑。 使用函数作为命令 这种方式更简洁,直接将函数作为 command 属性值,无需注册命令。适用于不需要撤销/重做功能的简单操作。 移除菜单项 通过遍历 menuData 数组,找到匹配 name 属性的菜单项,使用 splice() 方法移除。 运行效果 页面右侧提供两个复选框选项,用于控制菜单项的添加和移除 勾选"添加 '设置单元格格式' 菜单项"后,右键菜单中会显示该选项,点击后会将选中单元格设置为红色背景 勾选"添加 '打开对话框' 菜单项"后,右键菜单中会显示该选项,点击后会弹出一个简单的对话框 取消勾选复选框后,对应的菜单项会从右键菜单中移除 所有操作仅影响表格区域(viewport),在行头、列头等其他区域右键不会显示这些自定义菜单项 API 参考 menuData 属性 表示上下文菜单的菜单项数组,每个菜单项遵循 JSON Schema 格式,支持以下属性: text:菜单项显示的文本 name:菜单项的唯一标识 command:命令名称(字符串)或执行函数 workArea:菜单项显示区域,可选值包括 viewport、rowHeader、colHeader、corner 等 register 方法 向命令管理器注册自定义命令。 name:命令名称(字符串) command:命令对象,包含 canUndo 和 execute 属性 key、ctrl、shift、alt、meta:可选,用于设置快捷键
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 2}); initSpread(spread); }; function initSpread(spread) { initEvents(spread); } function initEvents(spread) { document.getElementById('addFormatCells').onchange = function () { var commandRemoved = false; spread.contextMenu.menuData.forEach(function (item, index) { if (item && item.name === "markWithRedBg") { spread.contextMenu.menuData.splice(index, 1); commandRemoved = true; } }); if (commandRemoved) { return; } var commandManager = spread.commandManager(); var markWithRedBg = { text: "设置单元格格式", name: "markWithRedBg", command: "markWithRedBg", workArea: "viewport" }; spread.contextMenu.menuData.push(markWithRedBg); var markWithRedBgCommand = { canUndo: false, execute: function () { var style = new GC.Spread.Sheets.Style(); style.name = 'style1'; style.backColor = 'red'; var sheet = spread.getActiveSheet(); sheet.suspendPaint(); var selections = sheet.getSelections(); var selectionIndex = 0, selectionCount = selections.length; for (; selectionIndex < selectionCount; selectionIndex++) { var selection = selections[selectionIndex]; for (var i = selection.row; i < (selection.row + selection.rowCount); i++) { for (var j = selection.col; j < (selection.col + selection.colCount); j++) { sheet.setStyle(i, j, style, GC.Spread.Sheets.SheetArea.viewport); } } } sheet.resumePaint(); } }; commandManager.register("markWithRedBg", markWithRedBgCommand, null, false, false, false, false); }; document.getElementById('addOpenDialog').onchange = function () { var commandRemoved = false; spread.contextMenu.menuData.forEach(function (item, index) { if (item && item.name === "openDialog") { spread.contextMenu.menuData.splice(index, 1); commandRemoved = true; } }); if (commandRemoved) { return; } var openDialog = { text: "打开对话框", name: "openDialog", command: showLoginDialog, workArea: "viewport" }; spread.contextMenu.menuData.push(openDialog); }; } function showLoginDialog() { if (document.getElementsByClassName('loginBox').length === 0) { var loginBox = document.createElement('div'); loginBox.className = 'loginBox'; loginBox.innerHTML = '<label for="Dialog" class="loginBoxLabel">对话框</label>' + '<input type="button" id="okBtn" class="btn-primary button" value="确定">' + '<input type="button" id="cancelBtn" class="btn-primary button" value="取消">'; document.body.appendChild(loginBox); document.getElementById('okBtn').onclick = function (){ loginBox.style.display = 'none'; }; document.getElementById('cancelBtn').onclick = function (){ loginBox.style.display = 'none'; }; } var loginBoxEle = document.getElementsByClassName('loginBox')[0]; if (loginBoxEle.style.display === 'none') { loginBoxEle.style.display = 'block'; } }
<!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"> <p>右键单击任意单元格以打开其上下文菜单。然后,您可以添加或移除以下演示选项之一:</p> <div id="settingsDiv"> <div class="option-row"> <input id="addFormatCells" type="checkbox" /> <label for="addFormatCells">添加 "设置单元格格式" 菜单项</label> </div> <div class="option-row"> <input id="addOpenDialog" type="checkbox" /> <label for="addOpenDialog">添加 "打开对话框" 菜单项</label> </div> </div> </div> </div> </body> </html>
.option-row { font-size: 14px; padding: 5px; margin-top: 10px; } .buttonStyle{ width:240px; height:30px; } .loginBox { position: absolute; left: 35%; top: 30%; background-color: white; padding: 20px; border: 1px solid #c6c6c6; box-shadow: rgba(0, 0, 0, 0.4) 1px 2px 5px; z-index: 2000; height: 100px; width: 200px; } .loginBoxLabel { display: inline-block; width: 200px; text-align: center; } .button{ width: 30%; margin: 60px 10%; text-align: center; } .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; margin-top: 10px; } label { margin-bottom: 6px; } input { padding: 4px 6px; } input[type=button] { margin-top: 6px; } p{ padding:2px 10px; background-color:#F4F8EB; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }