ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Handsontable 单元格选择完全指南:selectionMode、选择 API 与选区样式控制

Handsontable 单元格选择完全指南:selectionMode、选择 API 与选区样式控制 前端UI组件【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址https://gitcode.com/gh_mirrors/ha/handsontable点击查看免费下载Handsontable 的 Selection选择功能允许用户以单格、连续区域或非连续多区域的方式选取单元格并支持开发者通过 API 程序化读取、修改与设置选区。本文以 selection.md 为主线结合仓库内的可运行示例与核心源码完整讲解selectionMode、selectCell()/getSelected()等 API、选区样式、缩放手柄、键盘环绕导航等全部能力帮助你在 React、Vue、Angular 或原生 JavaScript 项目中落地可用的选择交互。Overview选择功能能做什么Selection 让用户可以在 Handsontable 网格中选中单个单元格或一片单元格区域。选中之后你可以通过 API 读取被选中单元格的数据编辑选中单元格的内容修改选中单元格的样式例如追加 CSS 类或改变背景色。Handsontable 的选择功能由内置的 Selection 模块驱动核心逻辑位于 handsontable/src/selection含 28 个 TypeScript 文件与大量 JS 测试对外则通过 core.ts 暴露selectCell()、getSelected()、getSelectedRange()等实例方法。用户侧的选择操作鼠标拖拽、键盘扩展与程序化选择走的是同一套选区状态机因此两者的行为保持一致。基础配置单格、区域与非连续多区域默认情况下你可以选中单个单元格或一片连续区域。基础交互规则如下在Mac上按住⌘或在Windows上按住Ctrl再点击单元格可以选择非相邻的多个区域点击列头可以选中整列所有单元格前提是启用了colHeaders点击行头可以选中整行所有单元格前提是启用了rowHeaders。这一默认行为由selectionMode选项控制其取值在 settings.ts 中定义共有三种模式取值行为single一次只能选中单个单元格range可以在单个连续区域内选中多个单元格multiple可以选中多个互不连续的区域下面的示例展示了如何在运行时通过updateSettings()动态切换这三种模式完整代码见 example1.js 与 example1.htmlimport Handsontable from handsontable/base; import { registerAllModules } from handsontable/registry; registerAllModules(); const container document.querySelector(#example1); const hot new Handsontable(container, { data: [ [A1, B1, C1, D1, E1, F1, G1, H1, I1], [A2, B2, C2, D2, E2, F2, G2, H2, I2], // ...更多数据行 ], width: auto, height: auto, colWidths: 100, rowHeaders: true, colHeaders: true, selectionMode: multiple, // 默认即可多选 autoWrapRow: true, autoWrapCol: true, licenseKey: non-commercial-and-evaluation, }); // 通过下拉菜单动态切换选择模式 hot.updateSettings({ selectionMode: single }); hot.updateSettings({ selectionMode: range }); hot.updateSettings({ selectionMode: multiple });提示示例中使用了handsontable/base与handsontable/registry的模块化注册方式这是仓库推荐的做法——按需注册模块可以显著减小打包体积。multiple 模式下 Ctrl点击的精确定义在multiple模式下Cmd/Ctrl 点击会向选区追加一个单元格。但当你点击一个已经被选中的单元格时行为取决于当前高亮highlight所处的位置规则如下若该单元格不持有高亮高亮会移动到该单元格上。该单元格保持选中其他所有已选中的单元格也保持不变。这让你可以在选区内部移动高亮而不丢失任何已选单元格。若该单元格已经持有高亮该单元格会被取消选中。如果点击的是最后一个剩余单元格则整个选区被清空。因此对同一个单元格连续做两次Cmd/Ctrl 点击依然会取消选中第一次点击把高亮移过去第二次点击将其移除。点击速度没有影响所以Cmd/Ctrl 双击与这两次单击效果完全相同。需要特别注意的是这条规则读取的是高亮位置而不是你是否能看到高亮因此即便用disableVisualSelection隐藏了高亮的视觉呈现上述行为依然一致。从选中区域读取数据要从选区中读取数据可以使用两个核心方法getSelected()返回视觉坐标的数组形如[[startRow, startCol, endRow, endCol], ...]getSelectedRange()返回CellRange对象的数组。在 core.ts 中getSelected()实际上是遍历selection.getSelectedRange().ranges把每个CellRange转成四元组坐标因此两者底层共享同一套选区数据。结合 example2.js读取选中单元格数据的完整做法如下const hot new Handsontable(container, { // ... selectionMode: multiple, outsideClickDeselects: false, // 点击网格外部时不取消选择 }); document.querySelector(#getButton).addEventListener(click, () { const selected hot.getSelected() || []; let data []; if (selected.length 1) { // 单一区域直接取出矩阵 data hot.getData(...selected[0]); } else { // 多区域逐个区域取数 for (let i 0; i selected.length; i 1) { data.push(hot.getData(...selected[i])); } } output.innerText JSON.stringify(data); });getData(row1, col1, row2, col2)会把指定矩形区域内的单元格内容以「数组的数组」形式返回非常适合后续做导出、批量计算或展示。修改选中的单元格拿到选区坐标后就可以批量修改其内容与样式。仓库示例 example3.js 演示了如何遍历所有选中区域把每个单元格的值改为data changed并追加一个c-redCSS 类const selected hot.getSelected() || []; hot.suspendRender(); // 暂停渲染批量操作后一次性重绘提升性能 for (let index 0; index selected.length; index 1) { const [row1, column1, row2, column2] selected[index]; const startRow Math.max(Math.min(row1, row2), 0); const endRow Math.max(row1, row2); const startCol Math.max(Math.min(column1, column2), 0); const endCol Math.max(column1, column2); for (let rowIndex startRow; rowIndex endRow; rowIndex 1) { for (let columnIndex startCol; columnIndex endCol; columnIndex 1) { hot.setDataAtCell(rowIndex, columnIndex, data changed); hot.setCellMeta(rowIndex, columnIndex, className, c-red); } } } hot.render(); hot.resumeRender();这里有两个值得注意的细节坐标规范化getSelected()返回的起止坐标不一定按大小排列因此示例中用Math.min/Math.max规范化出起始与结束行列并防止负索引越界。suspendRender()/resumeRender()批量修改时先挂起渲染全部写完后再重绘可以避免逐单元格触发的多次布局与重绘开销。自定义选区样式area 类与多层叠加选区的背景色由 CSS 类.area控制。当你通过Cmd/Ctrl 点击创建多个非相邻选区时每一层额外的选区会获得带编号的类第二层选区获得area-1第三层选区获得area-2依此类推。这些类是累积的——第二层选区中的单元格同时拥有area和area-1两个类。因此你可以利用 CSS 的叠加选择器为每一层设置不同的透明度或颜色见 example4.css/* 第一层选区——作用于所有被选中的单元格 */ #example4 td.area { background-color: rgba(75, 137, 255, 0.2); } /* 第二层非相邻选区Ctrl/Cmd 点击 */ #example4 td.area.area-1 { background-color: rgba(75, 137, 255, 0.4); } /* 第三层非相邻选区 */ #example4 td.area.area-2 { background-color: rgba(75, 137, 255, 0.6); }配对的初始化代码见 example4.js。层数越深蓝色越浓用户对「当前选中了哪几片区域」一目了然。需要说明的是目前没有简便方法修改选区的边框颜色——这是官方文档明确指出的限制。若确有定制边框的需求需要通过更底层的渲染钩子如afterDrawSelection自行实现。用缩放手柄调整选区设置selectionHandles为true后鼠标悬停在已选中的区域上会在每条边的中点显示一个药丸形手柄。拖动手柄即可移动对应边、调整选区大小。手柄只调整选中范围不会移动、填充或修改任何单元格数据。启用方式selectionHandles: true,该选项是网格级配置默认值为false。仓库中的完整演示见 example7.js其中还预先用hot.selectCell(1, 1, 4, 3)选中了表格内部的一个区域让手柄立即可见。使用时有以下限制手柄仅出现在桌面端。触屏设备保留原有的原生选择手柄不受此选项影响当selectionMode为single时该选项不生效整行、整列或全选select-all的选区不显示手柄与网格边界齐平、或落在冻结窗格线fixedRowsTop、fixedRowsBottom、fixedColumnsStart上的边不会显示手柄手柄仅支持指针操作没有键盘等价物。需要键盘调整选区大小时请使用 Shift 方向键。通过拖拽移动选区将moveCells设为true后用户可以拖拽已选单元格区域的边框把该区域的数据移动或复制到新位置。其完整配置细节、限制、相关钩子与实时演示请参考 Move cells 指南。如果目标是移动整行或整列而不是任意区域请分别参考 Row moving 指南 与 Column moving 指南。移动操作会触发beforeMoveCells与afterMoveCells钩子可用于在移动前后拦截或同步业务数据。程序化选择selectCell 与 deselectCell除了用户交互你完全可以从代码里控制选区。核心方法有两个selectCell()选中单个单元格或一片区域deselectCell()清除当前选区。core.ts 中的selectCell()支持多种调用签名// 选中单个单元格第 2 行、第 4 列视觉坐标从 0 开始 hot.selectCell(2, 4); // 选中一个区域第 2 行第 4 列 到 第 3 行第 5 列 hot.selectCell(2, 4, 3, 5); // 若列定义了属性名也可以直接用属性名代替列索引 hot.selectCell(2, first_name); hot.selectCell(2, first_name, 3, last_name); // 额外参数是否滚动到选中单元格false 则不滚动、是否聚焦 hot.selectCell(2, 4, 3, 5, false); hot.selectCell(2, 4, 3, 5, null, false);仓库示例 example5.js 给出了带按钮的完整演示document.querySelector(#select-cell).addEventListener(click, () { // 选中单个单元格第 1 行、第 1 列即 B2 hot.selectCell(1, 1); }); document.querySelector(#select-range).addEventListener(click, () { // 选中一个区域第 1 行第 1 列 到 第 3 行第 3 列即 B2:D4 hot.selectCell(1, 1, 3, 3); }); document.querySelector(#deselect).addEventListener(click, () { hot.deselectCell(); });此外还有一批常用方法selectCells()一次传入多个区域、selectColumns()选中整列、selectRows()选中整行、selectAll()全选以及getSelectedLast()/getSelectedRangeLast()只取最后操作的那一层选区在多区域模式下非常有用。键盘环绕跨越网格边缘跳转默认情况下键盘导航到达网格边缘即停止。通过两个配置项可以让选区在越过边缘时跳到对侧形成环绕效果跨垂直边缘左右跳转设置autoWrapRow为true。当选区位于某行第一个单元格时按←当选区位于某行最后一个单元格时按→或Tab。跨水平边缘上下跳转设置autoWrapCol为true。当选区位于某列第一个单元格时按↑当选区位于某列最后一个单元格时按↓或Enter。example6.js 展示了通过复选框实时开关这两个选项的做法const hot new Handsontable(container, { data: [ [SKU-4821, Harbor Goods, Electronics, 142], [SKU-0093, Alpine Supply Co., Apparel, 67], // ... ], colHeaders: [SKU, Supplier, Category, Quantity], rowHeaders: true, autoWrapRow: true, autoWrapCol: true, licenseKey: non-commercial-and-evaluation, }); document.querySelector(#auto-wrap-row).addEventListener(change, (e) { hot.updateSettings({ autoWrapRow: e.target.checked }); }); document.querySelector(#auto-wrap-col).addEventListener(change, (e) { hot.updateSettings({ autoWrapCol: e.target.checked }); });注意这两个选项影响的是键盘导航的环绕行为与selectionMode互相独立可以任意组合使用。结果与钩子联动配置好上述选项后用户可以按照设定的模式单格 / 区域 / 多区域选择单元格程序化选择selectCell()等会立即生效并触发相应的选择钩子。仓库为选择功能提供了丰富的生命周期钩子常见的有afterSelection/afterSelectionEnd选区变化及结束后触发回调参数为行列坐标afterSelectionByProp/afterSelectionEndByProp当列使用属性名时以属性名形式回调afterDeselect取消选择后触发afterDrawSelection每个选区单元格绘制后触发常用于自定义视觉样式modifyTransformStart/modifyTransformEnd与afterModifyTransformStart/afterModifyTransformEnd选区变换扩展/收缩前后触发可干预键盘扩展的落点beforeMoveCells/afterMoveCells配合moveCells拖拽移动时触发afterOnSelectionHandleMouseDown拖拽选择手柄按下时触发。完整列表见文档末尾的 Related API reference 小节及 hooks.md。通过这些钩子你可以实现「选中即联动」的业务逻辑例如状态栏实时显示选中行列数、选中区域批量高亮、或选中变化后联动刷新侧边面板。键盘快捷键速查表官方文档提供了一张完整的选区快捷键对照表含 Excel / Google Sheets 兼容性标注WindowsmacOS动作ExcelSheetsCtrlA⌘A全选所有单元格✓✓CtrlShiftSpace⌘⇧Space全选单元格及表头✓✓CtrlSpace⌃Space选中整列✓✓ShiftSpace⇧Space选中整行✓✓CtrlShift↑⌘⇧↑扩展到当前列第一个单元格✓✓CtrlShift↓⌘⇧↓扩展到当前列最后一个单元格✓✓CtrlShift←⌘⇧←扩展到当前行最左侧单元格✓✓CtrlShift→⌘⇧→扩展到当前行最右侧单元格✓✓Shift方向键⇧方向键逐格扩展选区✓✓ShiftHome⇧Home扩展到当前行第一个非冻结单元格*✓✗ShiftEnd⇧End扩展到当前行最后一个非冻结单元格*✗✗ShiftPage Up⇧Page Up向上扩展一屏✓✓ShiftPage Down⇧Page Down向下扩展一屏✓✓CtrlEnter⌘Enter用活动单元格的值填充整个选中区域✗✓Delete/BackspaceDelete/Backspace清除选中单元格的内容✓✓表格脚注* 该动作取决于你的布局方向如 RTL 布局下左右语义互换** 存在多个选区层时只有最后一层选区会被扩展。相关 API 参考汇总配置选项autoWrapCol、autoWrapRow、fragmentSelection、disableVisualSelection、dragToScroll、moveCells、selectionHandles、selectionMode、outsideClickDeselects。核心方法deselectCell()、getSelected()、getSelectedLast()、getSelectedRange()、getSelectedRangeLast()、selectAll()、selectCell()、selectCells()、selectColumns()、selectRows()全部见 core.md。钩子afterMoveCells、afterDeselect、afterDrawSelection、afterModifyTransformEnd、afterModifyTransformStart、afterSelection、afterSelectionByProp、afterSelectionEnd、afterSelectionEndByProp、beforeMoveCells、afterOnSelectionHandleMouseDown、modifyTransformStart全部见 hooks.md。插件DragToScroll——选区拖到网格边缘附近时自动滚动视口与选择交互紧密配合。小结Handsontable 的选择能力覆盖了从「用户鼠标/键盘交互」到「程序化 API 控制」的完整闭环selectionMode决定交互模式.area系列 CSS 类控制多层选区视觉selectCell()/getSelected()家族方法读写选区坐标selectionHandles与moveCells提供手柄调整与拖拽移动autoWrapRow/autoWrapCol实现键盘环绕导航而丰富的选择钩子让选区变化可以无缝联动业务逻辑。无论是构建简单的数据表格还是复杂的电子表格式应用这套选择体系都能直接复用且四个主流框架原生 JS / React / Vue / Angular均有对应的开箱即用封装。赞分享前端UI组件【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址https://gitcode.com/gh_mirrors/ha/handsontable点击查看免费下载相关推荐开源屏幕录制神器Cap如何5分钟创建专业级教程视频开源屏幕录制神器Cap如何5分钟创建专业级教程视频 还在为录制屏幕教程而烦恼吗想要一个既美观又实用的开源解决方案Cap正是你需要的终极工具作为Loom的屏幕录制音视频桌面应用后端前端视频处理AI 应用移动开发LaTeX-Workshop环境变量配置3个隐藏技巧让你效率翻倍LaTeX Workshop环境变量配置3个隐藏技巧让你效率翻倍 还在为LaTeX编译失败而反复调试PATH吗每次切换项目都要重新配置工具路径LaTeX开发工具IDElayui表格行选择单选、多选与全选功能layui表格行选择单选、多选与全选功能 还在为表格行选择功能而烦恼本文将全面解析layui表格的行选择机制从基础配置到高级应用助你轻松实现单选、多选和前端UI组件上一篇终极PNG优化革命Oxipng如何用Rust多线程重塑图像压缩下一篇3分钟上手Sourcetrail三平台极速部署指南2025最新版创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进