用Draggable快速实现可排序列表:Sortable拖拽排序实战指南
2026/9/18 18:08:17 网站建设 项目流程

用Draggable快速实现可排序列表:Sortable拖拽排序实战指南

【免费下载链接】draggableThe JavaScript Drag & Drop library your grandparents warned you about.项目地址: https://gitcode.com/gh_mirrors/dr/draggable

Draggable是一款轻量级 JavaScript 拖拽库,内置 Sortable 模块,让你几行代码就能实现可排序列表拖拽排序,支持鼠标、触摸、原生拖拽和 Force Touch。本文带你从零上手 Sortable 拖拽排序,并掌握事件监听与排序动画等进阶技巧。

为什么选择 Draggable 实现拖拽排序?

拖拽排序是任务看板、待办列表、商品管理后台里的高频需求。市面上方案不少,但 Draggable(npm 包名@shopify/draggable,gzip 后仅 16KB 左右)有几个突出的优点:

  • API 简洁:一个构造器 + 一组事件回调,无需学习复杂概念
  • 多端输入:默认内置MouseSensorTouchSensor,天然支持触屏拖拽
  • 模块化Draggable负责底层拖拽,Sortable只管排序,职责清晰
  • 可插拔插件:排序动画、尺寸镜像等能力按需挂载,如 src/Plugins/

核心源码位于 src/Sortable/Sortable.js,它继承自Draggable,并额外追踪拖动项的起始索引与容器,这正是"排序"能力的来源。

一键安装:npm / yarn / CDN 三种方式

npm:

npm install @shopify/draggable --save

yarn:

yarn add @shopify/draggable

不装依赖也行,浏览器直接以 ES Module 或 UMD 方式引入即可,具体写法见根目录 README.md 的 Install 章节。

最快配置方法:3 行代码让列表可拖拽排序

Sortable的构造逻辑很直白:传入容器选择器,再用draggable选项指定可拖拽项的选择器。

import {Sortable} from '@shopify/draggable'; const sortable = new Sortable(document.querySelectorAll('ul'), { draggable: 'li', });

就这么简单。官方示例 src/Sortable/README.md 给出的就是这个最小用法。

⚠️关键前提:可拖拽元素必须是容器的直接子元素,这是 Sortable 的硬性要求(见 src/Sortable/README.md)。

Sortable 拖拽排序的 4 个核心事件

拖拽过程中,Sortable 会在底层drag:*事件之外再抛出 4 个排序专属事件(定义见 src/Sortable/SortableEvent/SortableEvent.ts):

事件触发时机可取消取消效果
sortable:start拖拽开始阻止拖拽开始
sortable:sort排序即将发生阻止排序(如容量限制)
sortable:sorted元素已在 DOM 中完成排序
sortable:stop拖拽结束携带oldIndex/newIndex

监听事件的推荐写法(参考 src/Sortable/README.md):

sortable.on('sortable:stop', (evt) => { console.log(`从第 ${evt.oldIndex} 位移动到第 ${evt.newIndex} 位`); // 在这里把新顺序同步给后端 });

💡实战建议:持久化排序结果时优先监听sortable:stop,此时oldIndexnewIndexoldContainernewContainer都已就绪,无需自己计算。

多容器拖拽排序:看板场景怎么做?

把多个容器都传给构造器即可实现跨容器移动(源码 src/Sortable/Sortable.js 的move函数会自动处理"同容器移动"与"跨容器移动"两种情况)。

官方多容器示例位于 examples/src/content/Sortable/MultipleContainers/index.js,其中有一个很实用的技巧——sortable:sort的取消机制做容量限制

sortable.on('sortable:sort', (evt) => { if (!capacityReached) return; // 目标容器已满,且拖拽源不是它自己 → 取消排序 if (evt.dragEvent.overContainer === sortable.containers[1]) { evt.cancel(); } });

对应 HTML 模板见 examples/src/content/Sortable/MultipleContainers/MultipleContainers.html。

进阶:为拖拽排序加丝滑动画

默认排序是"瞬移"的,稍显生硬。挂载SortAnimation插件后,被挤开的列表项会通过translate3d平滑位移(插件源码 src/Plugins/SortAnimation/SortAnimation.js):

import {Sortable, Plugins} from '@shopify/draggable'; const sortable = new Sortable(document.querySelectorAll('ul'), { draggable: 'li', sortAnimation: { duration: 200, // 动画时长(毫秒) easingFunction: 'ease-in-out', }, plugins: [Plugins.SortAnimation], });

两点注意(见 src/Plugins/SortAnimation/README.md):

  1. 该插件只与Sortable配合,目前只支持同一容器内排序;
  2. 不要与SwapAnimation插件同时使用,两者会冲突。

常用配置项速查清单

以下选项对Sortable全部生效(完整说明见 src/Draggable/README.md):

选项作用默认值
draggable可拖拽项的 CSS 选择器.draggable-source
handle限定只有某个"手柄"区域可触发拖拽null(整项可拖)
distance指针移动多少像素后才开始拖拽,适合可点击的列表项0
delay拖拽延迟,解决触屏滚动冲突{mouse: 0, touch: 100}
mirror拖拽镜像的行为配置,如constrainDimensions锁定尺寸
classes自定义各状态类名,方便写 CSS 高亮内置默认值

🎯 想让列表项既能点击又能拖?把distance设为 5~10,即可优雅区分两种手势。

常见问题:拖拽排序不生效怎么办?

  • 元素不是容器的直接子元素:最常见的原因,参考 examples/src/content/Sortable/SimpleList/SimpleList.html 中的ul > li结构;
  • 选择器不匹配draggable选项的类名必须与 HTML 中可拖拽项一致,可对照 examples/src/content/Sortable/SimpleList/index.js 检查;
  • 容器查找为空:示例代码里都有containers.length === 0的保护判断,初始化时机(如 DOM 未就绪)要留意。

写在最后

Draggable 的 Sortable 模块用最小的心智成本换来了完整的拖拽排序能力:单列表重排 3 行代码搞定,跨容器、容量限制、排序动画都有现成的事件与插件可用。更多可运行的场景(简单列表、多容器、变换布局)都可以参考 examples/src/content/Sortable/ 目录,本地运行示例只需在根目录执行yarn && yarn start(见 README.md)。

【免费下载链接】draggableThe JavaScript Drag & Drop library your grandparents warned you about.项目地址: https://gitcode.com/gh_mirrors/dr/draggable

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询