前端UI组件【免费下载链接】SortableReorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.项目地址https://gitcode.com/gh_mirrors/so/Sortable点击查看免费下载本文围绕 Sortable.js 官方插件 OnSpill 展开深入讲解其内置的两大溢出处理插件 ——RevertOnSpill拖拽项溢出后归位与RemoveOnSpill拖拽项溢出后移除的挂载方式、配置选项与事件回调并结合仓库源码剖析「溢出spill」判定与处理的内核实现。读完本文你将能够在列表拖拽场景中精确控制元素被拖出有效投放区Drop Target时的行为并理解 Sortable 插件体系Sortable.mount与插件事件分发的工作机理。一、OnSpill 是什么一组默认内置的溢出处理插件OnSpill 插件包位于 plugins/OnSpill实际代码集中在 OnSpill.js 中。该文件包含两个相互独立的插件RevertOnSpill启用后若被拖拽的元素溢出即被放置到某个有效 Sortable 投放目标之外它会回到拖拽前所在的原始位置RemoveOnSpill启用后若被拖拽的元素溢出它会从 DOM 中直接移除。两个插件既可以分别独立导入也可以使用默认导出包含两个插件的数组一次性传给Sortable.mount// plugins/OnSpill/OnSpill.js 末尾导出 export default [Remove, Revert]; // 默认导出插件数组 export { Remove as RemoveOnSpill, Revert as RevertOnSpill }; // 命名导出单插件其中Remove对应RemoveOnSpillRevert对应RevertOnSpill见 OnSpill.js。重要事实这两个插件属于 Sortable 的默认插件Default Plugins已经内置在默认的 UMD 与 ESM 构建产物中。这一点在仓库中有两处直接证据entry-defaults.js 中默认构建会主动挂载它们import { RemoveOnSpill, RevertOnSpill } from ../plugins/OnSpill; Sortable.mount(RemoveOnSpill, RevertOnSpill);项目根目录的 Sortable.js默认 UMD 构建与 Sortable.min.js 中均内嵌了pluginName: revertOnSpill与pluginName: removeOnSpill的实现主 README.md 的插件列表中也收录了 OnSpill。因此使用默认构建如直接引用Sortable.js或Sortable.min.js时你无需任何挂载步骤只需在配置项中开启对应开关即可。二、在模块化构建中挂载 OnSpill如果你使用的是按需加载的模块化 ESM 构建modular目录则需要手动挂载。官方推荐写法import { Sortable, OnSpill } from sortablejs/modular/sortable.core.esm; Sortable.mount(OnSpill);这里导入的OnSpill即默认导出[Remove, Revert]数组。在仓库的 modular/sortable.core.esm.js 末尾可以看到export { AutoScrollPlugin as AutoScroll, MultiDragPlugin as MultiDrag, OnSpill, Sortable, SwapPlugin as Swap }证实 core 构建确实导出了 OnSpill 供手动挂载对应的入口文件是 entry-core.js。也可以只挂载其中一个插件import { Sortable, RemoveOnSpill } from sortablejs/modular/sortable.core.esm; Sortable.mount(RemoveOnSpill); // 只启用移除行为注意Sortable.mount对同名插件有防重复挂载保护。在 PluginManager.js 中如果尝试挂载一个pluginName已存在的插件会抛出异常Sortable: Cannot mount plugin ${plugin.pluginName} more than once。所以在默认构建已自动挂载之上重复mount(OnSpill)会直接报错这一点在混用构建产物时需要留意。三、RevertOnSpill溢出后让元素回到原位3.1 功能与配置RevertOnSpill启用后拖拽元素一旦被放置到无效投放区之外会被还原到其拖拽前所在的原始位置。配置方式如下new Sortable(el, { revertOnSpill: true, // Enable plugin // Called when item is spilled onSpill: function(/**Event*/evt) { evt.item // The spilled item } });revertOnSpill: true即插件的启用开关同时也是插件的pluginName见 OnSpill.jsonSpill是溢出事件回调参数evt.item指向被判定为溢出的拖拽元素。3.2 源码原理如何精确回到原始位置从 OnSpill.js 的实现来看RevertOnSpill的还原逻辑分为两步第一步拖拽开始时记录起始索引function Revert() {} Revert.prototype { startIndex: null, dragStart({ oldDraggableIndex }) { this.startIndex oldDraggableIndex; }, ...插件通过dragStart事件钩子把oldDraggableIndex拖拽前元素在列表中的索引暂存在this.startIndex。第二步溢出时把元素插回原索引位置onSpill({ dragEl, putSortable }) { this.sortable.captureAnimationState(); if (putSortable) { putSortable.captureAnimationState(); } let nextSibling getChild(this.sortable.el, this.startIndex, this.options); if (nextSibling) { this.sortable.el.insertBefore(dragEl, nextSibling); } else { this.sortable.el.appendChild(dragEl); } this.sortable.animateAll(); if (putSortable) { putSortable.animateAll(); } },关键细节getChild从 src/utils.js 导入用于取回容器中startIndex位置处的子元素将其作为插入参照若该位置没有元素例如元素原本在列表末尾则退化为appendChild追加到末尾captureAnimationState()与animateAll()是 Sortable 动画系统见 src/Animation.js的接口先捕获动画状态再在 DOM 变更后统一播放动画使归位过程带有平滑的过渡效果而非生硬跳跃若putSortable存在元素曾短暂进入另一个 Sortable 列表则对那个列表也执行同样的捕获与动画保证两个列表的布局都能正确回滚。由此可以推断RevertOnSpill的还原是基于索引的精确还原——即使在拖拽过程中列表的其他元素发生了位移归位时依然以拖拽前记录的索引为基准插入。四、RemoveOnSpill溢出后直接移除元素4.1 功能与配置RemoveOnSpill启用后拖拽元素一旦溢出会从 DOM 中被删除。配置方式new Sortable(el, { removeOnSpill: true, // Enable plugin // Called when item is spilled onSpill: function(/**Event*/evt) { evt.item // The spilled item } });removeOnSpill: true即启用开关pluginName为removeOnSpill见 OnSpill.js与revertOnSpill一样溢出时同样触发onSpill回调evt.item为被移除的元素。4.2 源码原理从 DOM 摘除元素OnSpill.js 中的实现非常简洁function Remove() {} Remove.prototype { onSpill({ dragEl, putSortable }) { const parentSortable putSortable || this.sortable; parentSortable.captureAnimationState(); dragEl.parentNode dragEl.parentNode.removeChild(dragEl); parentSortable.animateAll(); }, drop };溢出时先通过captureAnimationState()捕获动画状态然后dragEl.parentNode.removeChild(dragEl)将元素从其当前父节点中摘除若元素已被放入其他列表则从putSortable对应容器中移除最后animateAll()让剩余元素以动画方式填补空缺。一个实用的推论RemoveOnSpill常被用于「垃圾桶」式交互——把列表元素拖到列表外即代表删除此时可以在onSpill回调中拿到evt.item做后续业务处理如记录删除、发起异步请求等。五、onSpill 事件与溢出判定机制5.1 事件回调无论启用哪个插件溢出发生时都会触发 Sortable 的onSpill事件回调回调参数是一个事件对象其中evt.item是被判定为溢出的拖拽元素。该事件是标准 Sortable 事件onSpill对应事件名spill与onStart、onEnd等事件同级使用。5.2 溢出是如何被判定出来的两个插件共用了同一个drop判定函数OnSpill.jsconst drop function({ originalEvent, putSortable, dragEl, activeSortable, dispatchSortableEvent, hideGhostForTarget, unhideGhostForTarget }) { if (!originalEvent) return; let toSortable putSortable || activeSortable; hideGhostForTarget(); let touch originalEvent.changedTouches originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent; let target document.elementFromPoint(touch.clientX, touch.clientY); unhideGhostForTarget(); if (toSortable !toSortable.el.contains(target)) { dispatchSortableEvent(spill); this.onSpill({ dragEl, putSortable }); } };其判定流程可拆解为四步确定投放目标容器putSortable || activeSortable—— 优先取元素被放入的目标 Sortable否则取当前活跃的 Sortable隐藏拖拽幽灵元素调用hideGhostForTarget()避免幽灵元素干扰命中检测命中检测从originalEvent兼容changedTouches取触摸点中取出坐标用document.elementFromPoint(clientX, clientY)得到指针正下方的真实 DOM 元素判定溢出若命中元素不包含在目标 Sortable 容器内!toSortable.el.contains(target)则判定为溢出——先dispatchSortableEvent(spill)触发onSpill回调再调用插件自身的this.onSpill(...)执行归位/移除逻辑。需要说明的是这个drop函数会挂载到插件原型上Revert.prototype.drop/Remove.prototype.drop由 Sortable 核心在放置drop阶段通过插件事件系统调用。编译版构建 Sortable.js 中保留了完全一致的实现可作为交叉验证。5.3 插件事件分发为什么需要开启开关才生效OnSpill 的行为依赖 Sortable 的插件事件系统。在 PluginManager.js 的pluginEvent中if ( sortable.options[plugin.pluginName] sortable[plugin.pluginName][eventName] ) { sortable[plugin.pluginName]eventName; }只有sortable.options[revertOnSpill]或removeOnSpill为真时对应插件的事件方法才会被调用。这解释了为什么必须显式配置revertOnSpill: true或removeOnSpill: true才能生效——插件虽已随默认构建挂载initializeByDefault默认为true见 PluginManager.js但开关未打开时核心不会把drop等事件分发给它。六、实战结合默认构建与事件回调的完整示例6.1 最小可用示例默认构建ul idlist liItem 1/li liItem 2/li liItem 3/li /ul script srcSortable.min.js/script script new Sortable(document.getElementById(list), { revertOnSpill: true, // 拖到列表外回到原位 onSpill: function(evt) { console.log(spilled item:, evt.item); } }); /script由于默认构建已自动挂载 OnSpill以上代码开箱即用。6.2 移除型交互new Sortable(document.getElementById(list), { removeOnSpill: true, // 拖到列表外从 DOM 移除 onSpill: function(evt) { // 在这里做业务处理evt.item 即将被移除 // 例如updateBackend(evt.item.dataset.id, deleted); } });6.3 模块化构建需手动挂载import { Sortable, OnSpill } from sortablejs/modular/sortable.core.esm; Sortable.mount(OnSpill); const list new Sortable(document.getElementById(list), { revertOnSpill: true });6.4 使用建议与注意事项两个开关可以同时开启吗从源码看Revert与Remove是独立的两个插件实例二者在溢出时会各自执行onSpill逻辑Revert归位、Remove删除。实际业务中建议二选一避免行为冲突。onSpill与onEnd的关系溢出属于一种特殊的放置结果onSpill在drop阶段与spill事件一起触发可用它替代onEnd中「判断是否拖出列表」的繁琐逻辑。幽灵元素对命中检测的影响判定过程中先hideGhostForTarget()再取elementFromPoint这是为了保证命中结果是真实页面元素而非拖拽中的幽灵节点——如果你自定义了 ghost 相关行为注意保持该时序不被破坏。七、总结OnSpill 插件包通过RevertOnSpill与RemoveOnSpill两个默认插件为 Sortable.js 提供了开箱即用的溢出处理能力要么将拖拽元素精确还原到起始索引位置依赖startIndex记录与getChild/insertBefore的索引级归位要么直接从 DOM 中移除removeChild 动画补位。溢出判定由共享的drop函数完成隐藏幽灵 →elementFromPoint命中检测 → 判断目标容器是否包含命中点 → 触发spill事件与插件onSpill逻辑。无论你使用默认构建免挂载直接配revertOnSpill/removeOnSpill: true还是模块化构建先Sortable.mount(OnSpill)只需一份配置即可获得完整的溢出处理并通过onSpill回调接入自己的业务逻辑。相关的实现与测试素材可继续在 plugins/OnSpill/OnSpill.js、src/PluginManager.js、entry-defaults.js 与 Sortable.js 中深入查阅。赞分享前端UI组件【免费下载链接】SortableReorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.项目地址https://gitcode.com/gh_mirrors/so/Sortable点击查看免费下载相关推荐BinExp项目深入解析栈溢出问题原理与实战应用BinExp项目深入解析栈溢出问题原理与实战应用 前言 在二进制安全领域栈溢出是最基础也是最经典的问题类型之一。本文将基于BinExp项目中的Lectureoauth2-proxy 接入 Microsoft Entra ID 实战指南OIDC 配置、组溢出处理与 Workload Identityoauth2 proxy 接入 Microsoft Entra ID 实战指南OIDC 配置、组溢出处理与 Workload Identity 本文基于 oa后端API网关认证鉴权QQ空间说说备份完整指南2条命令历史说说全进ExcelQQ空间说说备份完整指南2条命令历史说说全进Excel 跑完一遍你会在本地磁盘拿到一整套 Excel 文件说说、转发、留言、好友全在里面配图单独存一个网页爬虫数据分析上一篇使用 Meshery Catalog 部署 Kubernetes 架构设计从设计文件到可视化落地下一篇Gyroflow视频防抖教程:把抖动的GoPro素材变成稳定的画面创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考