快速开始
快速开始 使用 NPM 安装:
npm install sortablejs --save
使用 Bower 安装:
bower install --save sortablejs
导入到您的项目中:
// 默认的 SortableJS
import Sortable from 'sortablejs';
// 核心 SortableJS (不含默认插件)
import Sortable from 'sortablejs/modular/sortable.core.esm.js';
// 完整的 SortableJS (包含所有插件)
import Sortable from 'sortablejs/modular/sortable.complete.esm.js';
挑选插件:
// 挑选额外的插件
import Sortable, { MultiDrag, Swap } from 'sortablejs';
Sortable.mount(new MultiDrag(), new Swap());
// 挑选默认插件
import Sortable, { AutoScroll } from 'sortablejs/modular/sortable.core.esm.js';
Sortable.mount(new AutoScroll());
用法
<ul id="items">
<li>项目 1</li>
<li>项目 2</li>
<li>项目 3</li>
</ul>
var el = document.getElementById('items');
var sortable = Sortable.create(el,Options);
您可以使用任何元素作为列表及其元素,而不仅仅是 ul 和 li。这里有一个使用 div 的例子。
📋 配置项 (Options)
基础配置
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
group | String/Object | "default" | 分组名称,相同分组可以互相拖拽 |
sort | Boolean | true | 是否允许在列表内排序 |
disabled | Boolean | false | 是否禁用拖拽功能 |
store | Object | null | 存储配置,用于保存和恢复排序状态 |
animation | Number | 0 | 动画持续时间(毫秒) |
easing | String | null | 动画缓动函数,如 "cubic-bezier(1, 0, 0, 1)" |
handle | String | null | 拖拽手柄选择器,只有点击此元素才能拖拽 |
filter | String/Function | null | 过滤器,匹配的元素不可拖拽 |
preventOnFilter | Boolean | true | 触发过滤器时是否阻止默认事件 |
draggable | String | null | 可拖拽元素的选择器 |
dataIdAttr | String | "data-id" | 元素ID的数据属性名 |
ghostClass | String | "sortable-ghost" | 拖拽占位符的CSS类名 |
chosenClass | String | "sortable-chosen" | 被选中元素的CSS类名 |
dragClass | String | "sortable-drag" | 拖拽中元素的CSS类名 |
swapThreshold | Number | 1 | 交换阈值,0-1之间的值 |
invertSwap | Boolean | false | 是否反转交换逻辑 |
invertedSwapThreshold | Number | null | 反转交换的阈值 |
direction | String | null | 排序方向:"vertical"、"horizontal" 或自动检测 |
forceFallback | Boolean | false | 强制使用HTML5拖拽的备用方案 |
fallbackClass | String | "sortable-fallback" | 备用拖拽元素的CSS类名 |
fallbackOnBody | Boolean | false | 将备用元素附加到body |
fallbackTolerance | Number | 0 | 备用模式下的鼠标移动容差(像素) |
fallbackOffset | Object | {x: 0, y: 0} | 备用元素的偏移量 |
supportPointer | Boolean | true | 是否支持Pointer Events |
emptyInsertThreshold | Number | 5 | 空容器的插入阈值(像素) |
滚动相关配置
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
scroll | Boolean/Element | true | 是否启用自动滚动 |
scrollFn | Function | null | 自定义滚动函数 |
scrollSensitivity | Number | 30 | 触发滚动的边距(像素) |
scrollSpeed | Number | 10 | 滚动速度 |
bubbleScroll | Boolean | true | 是否允许滚动冒泡到父容器 |
forceAutoScrollFallback | Boolean | false | 强制使用自动滚动的备用方案 |
多选相关配置
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
multiDrag | Boolean | false | 是否启用多选拖拽 |
selectedClass | String | "sortable-selected" | 选中项的CSS类名 |
multiDragKey | String | null | 多选按键:"ctrl"、"alt"、"shift" |
avoidImplicitDeselect | Boolean | false | 避免隐式取消选择 |
分组配置详细说明
当 group 为对象时,可以包含以下属性:
group: {
name: "shared", // 分组名称
pull: true, // 是否可以从此列表拖拽出元素 (true/false/function/"clone")
put: true, // 是否可以放入元素到此列表 (true/false/function/array)
revertClone: false // 克隆模式下是否还原克隆元素
}
🛠️ 方法 (Methods)
实例方法
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
option(name, value?) | name: String, value?: Any | Any | 获取或设置配置项 |
closest(el, selector?) | el: Element, selector?: String | Element | 查找最近的匹配元素 |
toArray() | - | String[] | 获取元素的data-id数组 可通过配置项dataIdAttr修改放入一个数组,并返回这个数组中 |
sort(order, useAnimation?) | order: String[], useAnimation?: Boolean | void | 按指定顺序排序元素 |
save() | - | void | 保存当前排序状态 |
destroy() | - | void | 销毁Sortable实例 |
静态方法
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
Sortable.create(el, options?) | el: Element, options?: Object | Sortable | 创建Sortable实例 |
Sortable.get(el) | el: Element | Sortable | 获取元素的Sortable实例 |
Sortable.mount(...plugins) | ...plugins: Plugin[] | void | 挂载插件 |
Sortable.utils | - | Object | 实用工具集合 |
工具方法 (Sortable.utils)
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
on(el, event, fn) | el: Element, event: String, fn: Function | void | 添加事件监听器 |
off(el, event, fn) | el: Element, event: String, fn: Function | void | 移除事件监听器 |
css(el, prop, val?) | el: Element, prop: String, val?: String | String/void | 获取或设置CSS属性 |
find(ctx, tagName, iterator?) | ctx: Element, tagName: String, iterator?: Function | Element[] | 查找子元素 |
bind(ctx, fn) | ctx: Object, fn: Function | Function | 绑定上下文 |
is(el, selector) | el: Element, selector: String | Boolean | 检查元素是否匹配选择器 |
closest(el, selector, ctx?) | el: Element, selector: String, ctx?: Element | Element | 查找最近的匹配祖先元素 |
clone(el) | el: Element | Element | 克隆元素 |
toggleClass(el, name, state?) | el: Element, name: String, state?: Boolean | void | 切换CSS类 |
detectDirection(el) | el: Element | String | 检测排列方向 |
📢 事件 (Events)
拖拽生命周期事件
| 事件名 | 触发时机 | 参数说明 |
|---|---|---|
onChoose | 选择元素开始拖拽时 | evt.oldIndex - 原始索引 |
onUnchoose | 取消选择元素时 | evt.oldIndex - 原始索引 |
onStart | 开始拖拽时 | evt.oldIndex - 原始索引 |
onEnd | 拖拽结束时 | evt.oldIndex - 原始索引 evt.newIndex - 新索引 |
onAdd | 元素被添加到列表时 | evt.newIndex - 新索引 evt.item - 被添加的元素 |
onUpdate | 元素在列表内移动时 | evt.oldIndex - 原始索引 evt.newIndex - 新索引 |
onSort | 任何排序发生时 | evt.oldIndex - 原始索引 evt.newIndex - 新索引 |
onRemove | 元素被移除时 | evt.oldIndex - 原始索引 evt.item - 被移除的元素 |
onFilter | 尝试拖拽被过滤的元素时 | evt.item - 被过滤的元素 |
onMove | 拖拽移动过程中 | evt.dragged - 被拖拽的元素 evt.draggedRect - 拖拽元素的位置信息 evt.related - 相关元素 evt.relatedRect - 相关元素的位置信息 evt.willInsertAfter - 是否在后面插入 |
onClone | 克隆元素时 | evt.item - 原始元素 evt.clone - 克隆的元素 |
onChange | 拖拽导致列表改变时 | evt.newIndex - 新索引 evt.oldIndex - 原始索引 |
事件对象属性详解
每个事件回调函数都会接收一个事件对象,包含以下属性:
{
to: HTMLElement, // 目标列表元素
from: HTMLElement, // 源列表元素
item: HTMLElement, // 被拖拽的元素
clone: HTMLElement, // 克隆的元素(如果有)
oldIndex: Number, // 在源列表中的索引
newIndex: Number, // 在目标列表中的索引
oldDraggableIndex: Number, // 在可拖拽元素中的索引
newDraggableIndex: Number, // 在可拖拽元素中的新索引
pullMode: String, // 拉取模式 ("clone"/"true")
originalEvent: Event // 原始浏览器事件
}
💡 使用示例
基础配置示例
var sortable = Sortable.create(document.getElementById('items'), {
// 基础配置
group: 'shared',
animation: 150,
// 样式类名
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
// 拖拽限制
handle: '.drag-handle',
filter: '.no-drag',
// 滚动配置
scroll: true,
scrollSensitivity: 30,
scrollSpeed: 10,
// 事件处理
onStart: function(evt) {
console.log('开始拖拽:', evt.oldIndex);
},
onEnd: function(evt) {
console.log('拖拽结束:', evt.oldIndex, '->', evt.newIndex);
},
onMove: function(evt) {
// 自定义移动逻辑
return true; // 返回false阻止移动
}
});
高级分组配置示例
// 源列表(只能拖出,不能拖入)
Sortable.create(sourceList, {
group: {
name: 'shared',
pull: 'clone', // 克隆模式拖出
put: false // 不允许拖入
}
});
// 目标列表(只能拖入,不能拖出)
Sortable.create(targetList, {
group: {
name: 'shared',
pull: false, // 不允许拖出
put: true // 允许拖入
}
});
方法调用示例
// 获取排序数组
var order = sortable.toArray();
// 按指定顺序排序
sortable.sort(['item-1', 'item-3', 'item-2']);
// 获取配置项
var animationDuration = sortable.option('animation');
// 设置配置项
sortable.option('disabled', true);
// 销毁实例
sortable.destroy();
🔌 插件系统
SortableJS 支持插件扩展,常用插件包括:
- MultiDrag - 多选拖拽插件
- Swap - 交换模式插件
- AutoScroll - 自动滚动插件
// 加载插件
Sortable.mount(new MultiDragPlugin(), new SwapPlugin());
// 使用插件功能
var sortable = Sortable.create(el, {
multiDrag: true,
selectedClass: 'selected'
});
📝 注意事项
- 性能优化:对于大量元素,建议使用虚拟滚动或分页
- 移动端适配:在移动设备上可能需要设置
forceFallback: true - 内存管理:记得在不需要时调用
destroy()方法 - 事件冒泡:注意事件可能会冒泡,需要适当处理
- CSS样式:确保拖拽相关的CSS类有正确的样式定义