惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
aimingoo的专栏
aimingoo的专栏
爱范儿
爱范儿
D
Docker
I
InfoQ
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Vercel News
Vercel News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Tailwind CSS Blog
D
DataBreaches.Net
月光博客
月光博客
N
Netflix TechBlog - Medium
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
Visual Studio Blog
MyScale Blog
MyScale Blog
B
Blog
阮一峰的网络日志
阮一峰的网络日志
L
LangChain Blog
Recent Announcements
Recent Announcements
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学

博客园 - 前端路引

高精度计算插件 decimal.js 处理 JS 浮点数精度问题(0.1 + 0.2 !== 0.3) 浏览器 15 个常见指纹特征,使用插件 FingerprintJS 生成浏览器指纹 Web前端入门第 90 问:JavaScript 也能无中生有的创建音频 Web前端入门第 89 问:总结 8 种跨域通信处理方案 Web前端入门第 88 问:引入 JavaScript 的 script 标签究竟有多少用法? Web前端入门第 87 问:JavaScript 中 setInterval 和 setTimeout 细节 Web前端入门第 86 问:JavaScript 中的 Web Worker 为什么能提升代码性能? Web前端入门第 85 问:JavaScript 一个简单的 IndexedDB 数据库入门示例 Web前端入门第 84 问:JavaScript sessionStorage 那些容易踩坑的地方 Web前端入门第 83 问:JavaScript localStorage 有大小限制吗?溢出会怎样? Web前端入门第 82 问:JavaScript cookie 有大小限制吗?溢出会怎样? Web前端入门第 81 问:JavaScript cookie 的读写操作 Web前端入门第 80 问:JavaScript 哪些地方需要 try...catch 异常捕获 Web前端入门第 79 问:JavaScript async & await 的异步任务进化之路 Web前端入门第 78 问:JavaScript 比较少见的模版字符串用法 Web前端入门第 77 问:JavaScript 由程序触发绑定事件的几种方式 Web前端入门第 76 问:JavaScript 鼠标事件(mouse) enter/leave 和 over/out 区别 Web前端入门第 75 问:JavaScript 性能优化之事件委托(事件代理)原理 Web前端入门第 74 问:JavaScript 事件冒泡与事件捕获
还在痛苦前端的拖拽排序吗?SortableJS 轻松搞定
前端路引 · 2025-12-18 · via 博客园 - 前端路引

产品扔过来一个需求:这个列表需要实现拖拽排序,心里面慌不慌?

如果要手搓一个这个功能,那代码可就很感人了。

大概有这么些逻辑:鼠标按下 -> 开始拖动 -> 拖动中实时改变位置 -> 拖动结束判断是否允许释放 -> 不允许缩放怎么做 -> 允许缩放又怎么做。

要实现这一大堆逻辑,那画面很美~~


别慌,面向 github 编程,已经有人造了轮子,咱们用起来即可。

SortableJS

项目主页:https://github.com/SortableJS/Sortable
Star: 12.6k
大小:45.1kB (gzip 17.3kB)
开源协议:MIT

根据官方示例,此插件可以实现这些功能:

  1. 单列表拖拽排序。
  2. 多列表相互拖拽排序。
  3. 通过拖拽克隆复制节点到列表。
  4. 允许 A -> B 拖拽,但 B 不允许拖拽 A
  5. 允许指定拖拽位置,比如只有列表序号能拖拽排序。
  6. 禁止列表某些项拖拽。
  7. 允许设置可放置区域。
  8. 允许嵌套的拖拽排序。

基础示例

bootcdn 上的 Sortable 鱼目混珠的有点多,建议还是从 github 或者 npm 上面下载。

1

源码:

<ul class="list" id="sortable">
  <li class="item" data-id="item-1">1</li>
  <li class="item" data-id="item-2">2</li>
  <li class="item" data-id="item-3">3</li>
  <li class="item" data-id="item-4">4</li>
</ul>

<style>
  .list {
    list-style: none;
    padding: 0;
    width: 300px;
  }
  .item {
    margin: 8px 0;
    padding: 8px;
    border: 1px solid #999;
    color: #fff;
  }
</style>

<script src="https://registry.npmmirror.com/sortablejs/1.15.6/files/Sortable.min.js"></script>
<script>
// 初始化
new Sortable(document.getElementById('sortable'), {
  animation: 150,
  // 结束拖拽
  onEnd: function () {
    const list = this.toArray()
    console.log(JSON.stringify(list));
  },
})
</script>

可使用 data-id 属性自定义元素 ID,方便在 vue 项目中与数据关联。

多列表互动

使用 group 属性可对拖拽分组,同一组中的元素允许互动,也可设置 put: false 禁止放入。

2

源码:

<ul class="list1" id="sortable1">
  <li class="item" data-id="item-1">1</li>
  <li class="item" data-id="item-2">2</li>
  <li class="item" data-id="item-3">3</li>
  <li class="item" data-id="item-4">4</li>
</ul>
<ul class="list2" id="sortable2">
  <li class="item" data-id="item-1">1</li>
  <li class="item" data-id="item-2">2</li>
  <li class="item" data-id="item-3">3</li>
  <li class="item" data-id="item-4">4</li>
</ul>

<style>
  ul {
    list-style: none;
    padding: 0;
  }
  .list1 {
    display: flex;
    align-items: center;
  }
  .list1 .item {
    padding: 8px 16px;
    margin-right: 16px;
    border: 1px solid #999;
  }
  .list2 {
    width: 300px;
  }
  .list2 .item {
    margin: 8px 0;
    padding: 8px;
    border: 1px solid #999;
    color: #fff;
  }
</style>

<script src="https://registry.npmmirror.com/sortablejs/1.15.6/files/Sortable.min.js"></script>
<script>
new Sortable(document.getElementById('sortable1'), {
  group: {
    name: 'test-group',
    pull: 'clone',
    put: false // 不允许拖拽进这个列表
  },
  animation: 150,
  sort: false // 设为false,禁止sort
});

new Sortable(document.getElementById('sortable2'), {
  group: 'test-group',
  animation: 150
});
</script>

更多使用方式

官方文档:https://sortablejs.github.io/Sortable/

中文网:https://sortablejs.com/
配置项:https://sortablejs.com/options

npm 安装

npm install sortablejs --save

使用

// 默认引用
import Sortable from 'sortablejs';

// 模块化核心代码,不包含插件
// import Sortable from 'sortablejs/modular/sortable.core.esm.js';

// 模块化完整代码,包含所有插件
// import Sortable from 'sortablejs/modular/sortable.complete.esm.js';

// 初始化
new Sortable(document.getElementById('sortable'), {
  animation: 150,
  // 结束拖拽
  onEnd: function () {
    const list = this.toArray()
    console.log(JSON.stringify(list));
  },
})

模块化引入

import Sortable from 'https://registry.npmmirror.com/sortablejs/1.15.6/files/modular/sortable.complete.esm.js';

// 初始化
new Sortable(document.getElementById('sortable'), {
  animation: 150,
  // 结束拖拽
  onEnd: function () {
    const list = this.toArray()
    console.log(JSON.stringify(list));
  },
})

写在最后

拖拽排序这需求,一般在交互要求高的项目中,基本上都会遇到,手搓轮子虽然没啥难度,但实现起来的流程太复杂,基本上都是直接使用开源插件。

如果是 Vue 项目,可参考 https://github.com/SortableJS/Vue.Draggable,虽然都是同一家的代码,但这插件已年久失修(最近更新 2020 年),估计需要自己填坑。