SortableJS logo

SortableJS

框架无关的拖拽排序库,支持列表排序、跨列表拖拽、动画和触摸设备,是拖拽排序领域最成熟的解决方案。

精选工具拖拽排序框架无关拖拽库开源

框架无关的 JavaScript 拖拽排序库,基于 HTML5 Drag and Drop API,支持列表排序、跨列表拖拽、动画和触摸设备,是拖拽排序领域下载量最高的库。

SortableJS

框架无关的拖拽排序库,支持列表排序、跨列表拖拽、动画和触摸设备,是拖拽排序领域最成熟的解决方案。

技术简介说明

SortableJS 是一个成熟的、框架无关的 JavaScript 拖拽排序库,由 Konstantin Lebedev(RubaXa)创建,目前由 Owen Mills 维护。它是拖拽排序领域下载量最高、生态最广的库,npm 周下载量约 400 万次,GitHub 31,000+ Stars。

SortableJS 基于原生 HTML5 Drag and Drop API 构建,同时提供 Fallback 机制(克隆元素方式)兼容 IE9 等旧浏览器。库体积约 30KB(gzip),无框架依赖,可以在 React、Vue、Angular、jQuery 等任何框架中使用,或通过官方/社区封装层集成。

SortableJS 的核心设计理念是专注排序——它不处理通用拖拽(自由移动元素)或缩放手势,而是专注于"列表重排"这一核心场景,提供跨列表拖拽、克隆、交换、多选拖拽、动画等丰富功能。其庞大的框架封装生态(vue-draggable-plus、react-sortablejs 等)使其成为拖拽排序领域的"基础设施"级库。

基本信息

快速上手

安装

# npm
npm install sortablejs --save
 
# 或 CDN
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
 
# 模块化导入
npm install sortablejs --save

基础配置

import Sortable from 'sortablejs'
 
const el = document.getElementById('my-list')
 
const sortable = new Sortable(el, {
  animation: 150,          // 拖拽动画时长
  handle: '.drag-handle',  // 拖拽手柄选择器
  ghostClass: 'blue-background', // 拖拽占位样式
  group: 'shared',         // 跨列表拖拽分组
  onUpdate: function(evt) {
    // 元素在同列表内重新排序
    console.log('oldIndex:', evt.oldIndex, 'newIndex:', evt.newIndex)
  },
  onAdd: function(evt) {
    // 从其他列表拖入元素
    console.log('从列表拖入,newIndex:', evt.newIndex)
  },
})

最小示例

<!DOCTYPE html>
<html>
<head>
  <style>
    .sortable-ghost { opacity: 0.4; }
  </style>
</head>
<body>
  <ul id="items">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
  </ul>
 
  <script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
  <script>
    new Sortable(document.getElementById('items'), {
      animation: 150,
      onUpdate: function(evt) {
        console.log('排序更新:', evt.oldIndex, '->', evt.newIndex)
      }
    })
  </script>
</body>
</html>

核心概念与架构

架构设计

SortableJS 采用插件化架构,核心库提供基础排序能力,额外功能通过插件扩展:

┌─────────────────────────────────────┐
│          SortableJS 核心             │
│  (HTML5 DnD + Fallback 兼容)        │
├─────────────────────────────────────┤
│                                     │
│  ┌─────────┐  ┌─────────┐          │
│  │AutoScroll│  │OnSpill  │  ← 默认  │
│  │(自动滚动) │  │(溢出处理)│    内置  │
│  └─────────┘  └─────────┘          │
│                                     │
│  ┌─────────┐  ┌─────────┐          │
│  │MultiDrag│  │  Swap   │  ← 可选  │
│  │(多选拖拽)│  │ (交换)  │    插件  │
│  └─────────┘  └─────────┘          │
│                                     │
└─────────────────────────────────────┘

        框架封装层:
┌─────────────────────────────────────┐
│ react-sortablejs │ vue-draggable-plus │
│ angular-legacy   │ jquery-sortablejs  │
└─────────────────────────────────────┘

事件模型

SortableJS 提供完整的拖拽生命周期事件:

事件触发时机关键属性
onChoose元素被选中evt.oldIndex
onStart拖拽开始evt.oldIndex
onEnd拖拽结束(任何结果)item, to, from, oldIndex, newIndex
onAdd从其他列表拖入onEnd
onUpdate同列表内重排onEnd
onRemove拖出到其他列表onEnd
onSort任何变化(add + update + remove)onEnd
onMove拖拽中移动dragged, related, willInsertAfter
onFilter尝试拖拽被过滤的元素evt.item
onClone克隆元素创建evt.item, evt.clone

onMove 返回值控制行为:

  • false → 取消移动
  • -1 → 插入目标之前
  • 1 → 插入目标之后
  • true / void → 保持默认

Group 系统(跨列表拖拽)

new Sortable(listA, {
  group: {
    name: 'shared',     // 共享组名(两个列表必须相同)
    pull: true,         // true | false | 'clone' | 数组 | 函数
    put: true,          // true | false | 数组 | 函数
    revertClone: false  // 克隆元素是否回原位
  }
})
 
new Sortable(listB, {
  group: {
    name: 'shared',     // 相同的 name 才能互相拖拽
    pull: true,
    put: true
  }
})

插件系统

插件类型功能
AutoScroll默认内置拖拽到边缘时自动滚动容器
OnSpill默认内置元素拖放到无效目标时的行为处理
MultiDrag额外挂载多选拖拽,点击选中后一次拖动多项
Swap额外挂载交换模式,两项互换位置而非重排
import Sortable, { MultiDrag, Swap } from 'sortablejs'
Sortable.mount(new MultiDrag(), new Swap())

核心特性

  • 框架无关:纯 JavaScript 实现,可在任何框架中使用,或通过封装层集成
  • 触摸设备支持:原生支持所有触摸设备,delayOnTouchOnly 防止误触,touchStartThreshold 处理灵敏触摸屏
  • 跨列表拖拽:通过 group 配置实现任意列表间拖拽,支持单向/双向、克隆模式
  • Clone(克隆模式)pull: 'clone' 创建副本而非移动原件,适合文件管理器场景
  • MultiDrag(多选拖拽):点击选中多项,一次拖动所有选中项
  • Swap(交换模式):拖拽时两项互换位置而非传统插入排序
  • 动画系统:基于 CSS Transform 的流畅动画,animation 参数控制时长,easing 控制缓动
  • 自动滚动:拖拽到容器边缘时自动滚动,支持原生和 Fallback 模式
  • 拖拽过滤filter 选项阻止特定元素被拖拽(如按钮、输入框)
  • Fallback 机制:兼容 IE9 等不支持 HTML5 DnD 的旧浏览器
  • 模块化导入:支持 core / default / complete 三种导入模式,优化 tree-shaking
  • 持久化支持store 选项配合 localStorage 保存排序状态

生态图

                    ┌──────────────────┐
                    │    SortableJS    │  ← 核心库(框架无关)
                    │   (sortablejs)   │
                    └────────┬─────────┘
                             │
            ┌────────────────┼────────────────┐
            │                │                │
   ┌────────▼──────┐ ┌──────▼───────┐ ┌──────▼────────┐
   │ React 封装    │ │ Vue 封装     │ │ Angular 封装  │
   │ react-        │ │ vue-         │ │ angular-      │
   │ sortablejs    │ │ draggable-   │ │ legacy-       │
   │               │ │ plus ⭐推荐   │ │ sortablejs    │
   └───────────────┘ └──────────────┘ └───────────────┘

   插件生态:
   ┌──────────────────────────────────────────────┐
   │ • Sortable.MultiDrag (多选拖拽)              │
   │ • Sortable.Swap (交换模式)                    │
   │ • Sortable.AutoScroll (自动滚动,默认挂载)    │
   │ • Sortable.OnSpill (溢出处理,默认挂载)       │
   └──────────────────────────────────────────────┘

   社区衍生:
   ┌──────────────────────────────────────────────┐
   │ • vue-draggable-virtual-scroll-list          │
   │ • SortableTS (TypeScript 重写版)             │
   │ • R sortable 包 (Shiny 应用)                 │
   └──────────────────────────────────────────────┘

框架封装状态

封装框架状态推荐度
vue-draggable-plusVue 3 / Vue 2.7+✅ 活跃维护,尤雨溪推荐⭐⭐⭐⭐⭐
react-sortablejsReact⚠️ 停滞(1+ 年未更新)⭐⭐⭐
vuedraggableVue 2❌ 停止维护(6 年)
vue.draggable.nextVue 3❌ 已废弃
angular-legacy-sortablejsAngularJS 1.x❌ AngularJS 已停维护

适用场景

  • Todo 列表 / 任务列表:经典排序场景,支持动画、持久化、跨列表移动
  • 看板(Kanban):卡片在列间拖拽,Clone 模式支持"复制"语义
  • 表格行排序:支持表格行拖拽排序(大表格 500+ 行有性能瓶颈)
  • 文件管理器:跨容器拖拽 + 克隆模式天然适配文件移动/复制语义
  • 仪表盘小部件:拖拽调整布局顺序
  • 表单构建器:拖拽字段组件到画布(嵌套层级深时需额外处理)
  • 嵌套列表:支持两级嵌套排序(3+ 级有已知索引计算问题)

开发与工程化

开发流程

# 克隆仓库
git clone https://github.com/SortableJS/Sortable.git
cd Sortable
 
# 安装依赖
npm install
 
# 开发模式
npm run dev
 
# 构建
npm run build
 
# 测试
npm run test

项目结构

Sortable/
├── src/
│   ├── Sortable.js        # 核心排序逻辑
│   ├── EventDispatcher.js # 事件分发
│   └── utils.js           # 工具函数
├── plugins/
│   ├── AutoScroll.js      # 自动滚动插件
│   ├── OnSpill.js         # 溢出处理插件
│   ├── MultiDrag.js       # 多选拖拽插件
│   └── Swap.js            # 交换插件
├── mod/                   # 模块化构建输出
│   ├── sortable.core.esm.js   # 核心(不含插件)
│   ├── sortable.esm.js        # 默认(含标准插件)
│   └── sortable.complete.esm.js # 完整(含所有插件)
└── tests/

模块化构建

// 1. 默认导入(含标准插件)
import Sortable from 'sortablejs'
 
// 2. 核心导入(不含插件,自行挂载)
import Sortable from 'sortablejs/sortable.core.esm.js'
 
// 3. 完整导入(含所有插件)
import Sortable from 'sortablejs/sortable.complete.esm.js'

性能与安全

性能特点

列表规模表现说明
< 200 元素⭐⭐⭐⭐⭐ 流畅60fps,动画表现优秀
200–500 元素⭐⭐⭐⭐ 可用偶有掉帧,建议设置 draggable 选择器
500+ 元素⭐⭐ 瓶颈明显卡顿,需配合虚拟化方案
2000+ 元素⭐ 不可用浏览器卡死,必须使用虚拟化

性能优化建议

  1. 设置 draggable 选择器:限制可拖拽元素,避免不必要的处理

    new Sortable(el, { draggable: '.item' })
  2. filter 过滤交互元素:在库层面阻止按钮、输入框的拖拽

    new Sortable(el, { filter: '.ignore-elements' })
  3. fallbackTolerance: 3-5:防止点击误触拖拽

  4. 大列表配合虚拟滚动:使用 react-window / vue-virtual-scroll-list 等

  5. 动画适度animation: 150 是合理默认值,过长动画增加感知延迟

安全注意事项

  • SortableJS 不涉及用户输入,无 XSS 风险
  • 拖拽排序状态持久化时注意数据校验
  • forceFallback 模式下克隆元素注意内存泄漏

已知性能瓶颈

  • 大列表(500+):DOM 计算和动画性能下降明显(Issue #1723
  • 不支持原生虚拟化:需自行集成第三方虚拟滚动库,集成复杂度高
  • 嵌套列表:3+ 级嵌套时索引计算不可靠

技术对比

与拖拽排序库对比

维度SortableJSdnd-kitDragulainteract.js
框架框架无关React 专用框架无关框架无关
包体积~30KB~6KB~5KB~40KB
无障碍⚠️ 基础✅ 内建 WCAG 2.1❌ 无❌ 无
TypeScript⚠️ @types/sortablejs✅ 原生⚠️ @types✅ 内建
触摸支持✅ 原生✅ 原生❌ 有限✅ 原生
跨列表拖拽✅ 原生✅ 支持✅ 原生⚠️ 需手写
动画✅ 内建⚠️ 需配置✅ 内建❌ 无
缩放/手势❌ 不支持❌ 不支持❌ 不支持✅ 完整支持
维护状态维护模式✅ 活跃❌ 基本停止⚠️ 低活跃
周下载量~400 万~280 万~50 万~57 万

选型建议

场景推荐
框架无关的排序SortableJS(首选)
Vue 3 排序vue-draggable-plus(基于 SortableJS)
React 排序dnd-kit(更现代)
需要缩放/手势interact.js
极简拖拽Dragula(但已不活跃)

最佳实践

生产环境最佳实践

  1. 模块化导入:使用 core build + 按需挂载插件,减少包体积

    import Sortable from 'sortablejs/sortable.core.esm.js'
    import { MultiDrag } from 'sortablejs/plugins'
    Sortable.mount(new MultiDrag())
  2. 设置 draggable 选择器:限制可拖拽元素范围

    new Sortable(el, { draggable: '.sortable-item' })
  3. 使用 filter 过滤:阻止按钮、输入框等交互元素被拖拽

    new Sortable(el, {
      filter: '.btn, input, a',
      preventOnFilter: false
    })
  4. fallbackTolerance: 3-5:防止点击时误触发拖拽

    new Sortable(el, { fallbackTolerance: 5 })
  5. 组件卸载时销毁实例:防止内存泄漏

    const sortable = new Sortable(el, options)
    // 组件卸载时
    sortable.destroy()
  6. 嵌套列表使用 fallbackOnBody: true

    new Sortable(nestedEl, {
      fallbackOnBody: true,
      swapThreshold: 0.65
    })
  7. 持久化排序状态

    new Sortable(el, {
      store: {
        get: (sortable) => {
          const order = localStorage.getItem(sortable.options.group.name)
          return order ? order.split('|') : []
        },
        set: (sortable) => {
          const order = sortable.toArray()
          localStorage.setItem(sortable.options.group.name, order.join('|'))
        }
      }
    })

常见陷阱

陷阱说明解决方案
Vue/React 响应性冲突SortableJS 直接操作 DOM,与框架虚拟 DOM 冲突在事件中同步框架状态,使用官方封装层
嵌套列表索引错乱3+ 级嵌套时 newIndex 不准确使用 oldDraggableIndex / newDraggableIndex
delay 在 IE/Edge 无效原生 DnD 不支持延迟使用 forceFallback: true
跨列表拖拽不生效忘记设置相同 group.name确保两侧 group 配置一致
动态 DOM 排序失效动态增删元素后排序失效调用 sortable.sort() 或重新初始化
空列表无法放置空列表无放置区域使用 CSS :empty + padding 提供放置区

技术局限与边界

已知限制

限制严重程度说明
Shadow DOM 不支持🔴 严重事件重定向和 elementFromPoint 跨边界失效(Issue #2128
大列表性能🔴 严重500+ 元素明显卡顿,2000+ 基本不可用
无原生虚拟化🟡 中等需自行集成第三方虚拟滚动库
iframe 拖拽🟡 中等仅同源 iframe;触摸设备跨 iframe 完全不可用
3+ 级嵌套列表🟡 中等深层嵌套拖拽不可靠,索引计算错误
无障碍(A11y)🟡 中等无内置 ARIA、无键盘拖拽、无屏幕阅读器通知
单人维护风险🟡 中等核心维护者 Owen Mills 为唯一活跃贡献者
不支持自由拖拽🟢 设计限制仅支持排序语义,不支持自由移动元素到任意位置

不适用场景

  • 自由拖拽(画布、白板)→ 推荐 interact.js 或 dnd-kit
  • 缩放/旋转手势 → 推荐 interact.js
  • 文件上传 Dropzone → 推荐 react-dropzone
  • 超大数据列表(>1000) → 需配合虚拟化方案,集成复杂
  • 对无障碍要求高的项目 → 推荐 dnd-kit

学习资源

2026 年现状

版本发布时间线

版本日期间隔
v1.15.32024 年中
v1.15.52024-11-28
v1.15.62025-05-296 个月
v1.15.72026-02-118.5 个月

维护状态

指标评估
发布频率🟡 低(约 6-8 个月一个版本)
维护模式维护/修补模式 — 有 bug 修复,无重大新功能
核心维护者Owen Mills(owen-m1)为唯一活跃提交者
社区活跃度✅ 485 open issues、38 open PRs、活跃 Discussions
npm 下载量✅ ~400 万/周,生态影响力巨大

发展趋势

  • 稳定但进化缓慢:核心功能成熟,但缺少 A11y、Shadow DOM 等现代需求
  • 生态依赖深:vue-draggable-plus、react-sortablejs 等均依赖核心库
  • 单人维护风险:Owen Mills 为唯一活跃维护者,如离开则项目可能停滞
  • 新项目选型分化:React 项目推荐 dnd-kit;Vue 3 项目推荐 vue-draggable-plus;框架无关场景仍是 SortableJS

选型结论

SortableJS 在 2026 年仍处于「维护模式」,是成熟稳定、广泛使用但进化缓慢的库。 对于框架无关的拖拽排序场景,它仍然是最成熟的选择。但纯 React 项目应优先考虑 dnd-kit,Vue 3 项目应使用 vue-draggable-plus。