完全指南:从 `columnDrag` 配置到源码级移动原理)
前端UI组件【免费下载链接】ceJspreadsheet is a lightweight JavaScript data grid component for creating interactive data grids with advanced spreadsheet controls.项目地址https://gitcode.com/gh_mirrors/ce/ce点击查看免费下载本文是 Jspreadsheet CE轻量级 JavaScript 数据网格组件列拖拽功能的实战指南。你将掌握如何在原生 JavaScript、React、Vue 三种环境中开启columnDrag理解拖拽起始、目标定位、落点判定与moveColumn底层调用链的完整实现并学会如何结合合并单元格、右键菜单与onmovecolumn事件安全地使用这一交互能力。一、功能概览默认行为与配置开关Jspreadsheet CE 的列拖拽允许用户用鼠标按住表头并左右拖动从而改变整列表头、单元格数据、列宽、脚注等的位置。该交互能力的开关由工作表级配置项columnDrag: boolean控制配置项说明默认值columnDrag: boolean是否允许通过拖拽改变列位置见下文版本差异说明需要特别注意的是版本间的默认值差异在 v4 及更早版本中列拖拽默认是禁用的必须显式设置columnDrag: true才能开启参见 v4 示例 的说明在 v5当前 CE 主版本中该属性的默认值已调整为true这一变更记录在 升级指南 中官方 列配置文档 同样标注该属性默认值为true。因此本文关联文档中“默认禁用、需显式开启”的表述针对的是 v4 行为如果你升级到 v5即便不写columnDrag列拖拽也会默认可用。在下面的示例中我们仍统一显式传入columnDrag: true以便在任何版本中都能得到确定的行为。二、原生 JavaScriptHTML示例在纯浏览器环境中通过jspreadsheet()函数初始化即可。核心是在某个worksheets条目即工作表内设置columnDrag: truehtml script srchttps://bossanova.uk/jspreadsheet/v5/jspreadsheet.js/script script srchttps://jsuites.net/v5/jsuites.js/script link relstylesheet hrefhttps://jsuites.net/v5/jsuites.css typetext/css / link relstylesheet hrefhttps://bossanova.uk/jspreadsheet/v5/jspreadsheet.css typetext/css / link relstylesheet hrefhttps://fonts.googleapis.com/css?familyMaterialIcons / div idspreadsheet/div script jspreadsheet(document.getElementById(spreadsheet), { worksheets: [{ data: [ [BR, Cheese, 1], [CA, Apples, 0], [US, Carrots, 1], [GB, Oranges, 0], ], columns: [ { type: autocomplete, title: Country, width: 300, url: /jspreadsheet/countries.json }, { type: dropdown, title: Food, width: 150, source: [Apples,Bananas,Carrots,Oranges,Cheese] }, { type: checkbox, title: Stock, width:100 }, ], columnDrag: true, }] }); /script /html示例中的三个列类型都支持拖拽autocomplete国家列通过url异步加载候选项、dropdown食品列通过source提供静态选项、checkbox库存列。拖拽功能与列类型无关任何类型的列都可以被拖动。三、React 示例在 React 中使用官方封装组件jspreadsheet-ce/react将columnDrag作为属性传给Worksheet即可import React, { useRef } from react; import { Spreadsheet, Worksheet } from jspreadsheet-ce/react; import jsuites/dist/jsuites.css; import jspreadsheet-ce/dist/jspreadsheet.css; export default function App() { // Spreadsheet array of worksheets const spreadsheet useRef(); // Tabs const data [ [BR, Cheese, 1], [CA, Apples, 0], [US, Carrots, 1], [GB, Oranges, 0], ]; const columns [ { type: autocomplete, title: Country, width: 300, url: /jspreadsheet/countries.json }, { type: dropdown, title: Food, width: 150, source: [Apples,Bananas,Carrots,Oranges,Cheese] }, { type: checkbox, title: Stock, width:100 }, ]; return ( Spreadsheet ref{spreadsheet} Worksheet data{data} columns{columns} columnDrag{true} / /Spreadsheet ); }四、Vue 示例在 Vue 3 中使用jspreadsheet-ce/vue时同样把columnDrag绑定到Worksheet组件上。注意data、columns与columnDrag在模板中都以属性形式传入template Spreadsheet refspreadsheet Worksheet :datadata :columnscolumns :columnDragtrue / /Spreadsheet /template script import { ref } from vue; import { Spreadsheet, Worksheet } from jspreadsheet-ce/vue; import jsuites/dist/jsuites.css; import jspreadsheet-ce/dist/jspreadsheet.css; export default { components: { Spreadsheet, Worksheet }, setup() { // Spreadsheet reference const spreadsheet ref(null); // Data for the worksheet const data ref([ [BR, Cheese, 1], [CA, Apples, 0], [US, Carrots, 1], [GB, Oranges, 0], ]); // Columns definition for the worksheet const columns ref([ { type: autocomplete, title: Country, width: 300, url: /jspreadsheet/countries.json }, { type: dropdown, title: Food, width: 150, source: [Apples,Bananas,Carrots,Oranges,Cheese] }, { type: checkbox, title: Stock, width: 100 }, ]); return { spreadsheet, data, columns }; } } /script五、源码级原理从按下表头到列移动完成仅仅知道“打开开关”还不够理解底层实现能帮你预判各种边界行为例如与合并单元格、历史记录、表格公式引用的交互。Jspreadsheet CE 的列拖拽在 src/utils/events.js 和 src/utils/columns.js 中实现整体分为四个阶段。1. 启动阶段标记表头容器为可拖拽工作表初始化时worksheets.js 会根据配置给表头容器追加样式类if (obj.options.columnDrag ! false) { obj.thead.classList.add(draggable); }draggable类一方面用于 CSS 视觉提示另一方面在mousemove的悬停检测中用于决定是否显示move光标见 events.js。2. 起始判定鼠标按住表头底部边缘在mousedown处理器中events.js组件会先判断按下的位置是否满足拖拽触发条件——表头单元格底部 6 像素区域内} else if (libraryBase.jspreadsheet.current.options.columnDrag ! false info.height - e.offsetY 6) { if (isColMerged.call(libraryBase.jspreadsheet.current, columnId).length) { console.error(Jspreadsheet: This column is part of a merged cell.); } else { // Reset selection libraryBase.jspreadsheet.current.resetSelection(); // Drag helper libraryBase.jspreadsheet.current.dragging { element: e.target, column: columnId, destination: columnId, }; // Border indication libraryBase.jspreadsheet.current.headers[columnId].classList.add(dragging); ... } }这里有三个值得注意的细节触发区域只有表头底部 6px 高避免与列宽调整右侧 6px 区域触发columnResize见同文件第 230 行和表头单击选中/重命名第 273-288 行单击后延时 800ms 进入setHeader重命名冲突若被拖动的列属于合并单元格isColMerged命中组件会直接向控制台输出错误Jspreadsheet: This column is part of a merged cell.并拒绝开启拖拽拖拽开始时dragging助手对象记录column源列与destination目标列初始等于源列同时给表头和数据单元格添加dragging类做视觉高亮。3. 拖拽过程实时计算目标列在mousemove处理器中events.js组件根据鼠标在目标表头内的横向位置计算落点if (e.target.clientWidth / 2 e.offsetX) { // 鼠标位于目标列左半侧 if (libraryBase.jspreadsheet.current.dragging.column columnId) { libraryBase.jspreadsheet.current.dragging.destination parseInt(columnId) - 1; } else { libraryBase.jspreadsheet.current.dragging.destination parseInt(columnId); } libraryBase.jspreadsheet.current.headers[columnId].classList.add(dragging-left); } else { // 鼠标位于目标列右半侧 if (libraryBase.jspreadsheet.current.dragging.column columnId) { libraryBase.jspreadsheet.current.dragging.destination parseInt(columnId); } else { libraryBase.jspreadsheet.current.dragging.destination parseInt(columnId) 1; } libraryBase.jspreadsheet.current.headers[columnId].classList.add(dragging-right); }规则可概括为以被掠过表头的中线为分界鼠标在左半侧则目标列号向源列方向收敛-1在右半侧则向远离方向推进1同时通过dragging-left/dragging-right类给出插入位置的视觉指示。这里同样会对合并单元格做拦截检查。4. 落点执行moveColumn的完整副作用链鼠标松开时mouseup处理器events.js若源列与目标列不同组件调用moveColumn(源列号, 目标列号)。真正完成移动的是 columns.js 中的moveColumn函数它依次执行合并单元格保护若工作表中存在合并单元格且拖拽涉及合并列弹出确认框This action will destroy any existing merged cells. Are you sure?用户取消则返回false并中止第 306-321 行DOM 重排分别对表头容器、列宽容器以及每一行的数据单元格执行insertBefore把源列节点插入到目标位置第 326-340 行内部数组同步同步options.columns、headers、cols、options.data[j]、records[j]五个数组并重写受影响范围内每个单元格的x坐标第 342-362 行脚注同步若配置了footers脚注数组同步移动第 365-369 行历史记录写入{ action: moveColumn, oldValue: o, newValue: d }到历史栈使 CtrlZ 撤销可以还原本次移动第 372-376 行公式引用更新调用updateTableReferences修正表格中公式对移动后列位置的引用第 379 行事件派发触发onmovecolumn回调第 382 行。5. 关联事件onmovecolumnmoveColumn的最后一步会派发onmovecolumn(instance, oldColumn, newColumn, numOfColumnsMoved)事件。在 v5 中该事件新增了第四个参数表示一次移动涉及的列数量见 升级指南 的说明。你可以在工作表配置中监听它例如在列被拖动后执行额外的数据同步或界面更新jspreadsheet(document.getElementById(spreadsheet), { worksheets: [{ data: [[BR, Cheese, 1], [CA, Apples, 0]], columnDrag: true, onmovecolumn: function (instance, oldColumn, newColumn) { console.log(列已从 oldColumn 移动到 newColumn); } }] });六、与相邻交互能力的协同与取舍列拖拽并非孤立功能它与表头区域的多个交互共享同一个鼠标事件处理入口events.js使用时需留意以下协同关系列宽调整columnResize表头右侧 6px 内按下触发缩放表头底部 6px 内按下触发拖拽两者互不干扰列排序columnSorting默认开启右键表头菜单提供“升序/降序”排序见 events.js拖拽改变的是列序排序改变的是行序二者用途不同列重命名allowRenameColumn单击表头 800ms 后进入重命名模式拖拽不会误触重命名合并单元格涉及合并列的拖拽会被拦截或需用户确认这是为了防止破坏合并区域的结构撤销重做history列移动会被记录进历史栈可通过撤销快捷键恢复原位置。若你需要完全禁止拖拽例如在只读报表场景下显式设置columnDrag: false即可——源码中的判定都是! false因此false是唯一能关闭该能力的取值undefined、null等都会被当作开启处理。七、小结与延伸阅读配置要点columnDrag是工作表级配置v4 默认关闭v5 默认开启显式传值可以规避版本差异。三种接入方式原生 HTML 在worksheets[i]中配置React/Vue 作为Worksheet的属性传入。交互细节拖拽从表头底部边缘触发合并列会被拦截移动后会同步 DOM、数据、脚注、历史与公式引用并触发onmovecolumn事件。想进一步深入列相关能力可继续阅读列配置总览columns.mdcolumnDrag、columnResize、columnSorting、allowRenameColumn等完整属性表及moveColumn/insertColumn/deleteColumn方法说明v4 列拖拽示例了解旧版 API顶层data/columns而非worksheets包裹的写法差异v4 到 v5 升级指南查看columnDrag默认值变更及onmovecolumn参数更新的完整记录合并单元格文档其中多个示例展示了与columnDrag同时配置的典型场景。赞分享前端UI组件【免费下载链接】ceJspreadsheet is a lightweight JavaScript data grid component for creating interactive data grids with advanced spreadsheet controls.项目地址https://gitcode.com/gh_mirrors/ce/ce点击查看免费下载相关推荐Granite Guardian 3.0-2B核心功能解析从风险检测到幻觉识别Granite Guardian 3.0 2B核心功能解析从风险检测到幻觉识别 Granite Guardian 3.0 2B是一款基于Granite架构的轻前端UI组件TanStack Table Ember 列排序Column Ordering完整指南从状态配置到拖拽重排的实现原理TanStack Table Ember 列排序Column Ordering完整指南从状态配置到拖拽重排的实现原理 导读 本文基于 tanstack/前端UI组件react-dnd useDragLayer Hook 完全指南从自定义拖拽层到源码级原理react dnd useDragLayer Hook 完全指南从自定义拖拽层到源码级原理 useDragLayer 是 react dnd Hooks AP前端UI组件上一篇IoT-For-Beginners 地理围栏实战使用 Azure Functions 的 Twilio/SendGrid 绑定发送进入围栏通知下一篇IoT-For-Beginners 实战为 Wio Terminal 配置麦克风与扬声器智能语音定时器硬件篇创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考