Sortable 是一个用于可重新排序的拖放列表的 JavaScript 库。
Demo: http://sortablejs.github.io/Sortable/
@types/sortablejs
使用 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';
Cherrypick 插件:
// Cherrypick 额外插件
import Sortable, { MultiDrag, Swap } from 'sortablejs';
Sortable.mount(new MultiDrag(), new Swap());
// Cherrypick 默认插件
import Sortable, { AutoScroll } from 'sortablejs/modular/sortable.core.esm.js';
Sortable.mount(new AutoScroll());
<ul id="items">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
var el = document.getElementById('items');
var sortable = Sortable.create(el);
您可以使用任何元素作为列表及其元素,而不仅仅是 ul
/li
。这是一个使用 div
的示例。
var sortable = new Sortable(el, {
group: "name", // 或 { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }
sort: true, // 在列表内排序
delay: 0, // 定义排序开始时间(毫秒)
delayOnTouchOnly: false, // 仅在用户触摸时延迟
touchStartThreshold: 0, // 像素,在取消延迟拖动事件之前,点应移动的像素数
disabled: false, // 如果设置为 true,则禁用可排序对象。
store: null, // @see Store
animation: 150, // 毫秒,排序时移动项目的动画速度,`0` — 不使用动画
easing: "cubic-bezier(1, 0, 0, 1)", // 动画的缓动。默认为 null。示例请参阅 https://easings.net/。
handle: ".my-handle", // 列表项内的拖动手柄选择器
filter: ".ignore-elements", // 不会导致拖动的选择器(字符串或函数)
preventOnFilter: true, // 触发 `filter` 时调用 `event.preventDefault()`
draggable: ".item", // 指定元素内哪些项目应可拖动
dataIdAttr: 'data-id', // `toArray()` 方法使用的 HTML 属性
ghostClass: "sortable-ghost", // 放置占位符的 Class 名称
chosenClass: "sortable-chosen", // 所选项目的 Class 名称
dragClass: "sortable-drag", // 拖动项目的 Class 名称
swapThreshold: 1, // 交换区域的阈值
invertSwap: false, // 如果设置为 true,则始终使用反向交换区域
invertedSwapThreshold: 1, // 反向交换区域的阈值(将设置为(默认为 swapThreshold 值)
direction: 'horizontal', // Sortable 的方向(如果未指定,将自动检测)
forceFallback: false, // 忽略 HTML5 DnD 行为并强制启用 fallback
fallbackClass: "sortable-fallback", // 使用 forceFallback 时克隆的 DOM 元素的 Class 名
fallbackOnBody: false, // 将克隆的 DOM 元素附加到 Document 的 Body 中
fallbackTolerance: 0, // 指定鼠标在被视为拖动之前应移动的距离(以像素为单位)。
dragoverBubble: false,
removeCloneOnHide: true, // 当克隆元素未显示时,将其移除,而不是隐藏它
emptyInsertThreshold: 5, // 鼠标与空的 sortable 之间的距离,以便将拖动元素插入其中
setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {
dataTransfer.setData('Text', dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent
},
// Element is chosen
onChoose: function (/**Event*/evt) {
evt.oldIndex; // element index within parent
},
// Element is unchosen
onUnchoose: function(/**Event*/evt) {
// same properties as onEnd
},
// Element dragging started
onStart: function (/**Event*/evt) {
evt.oldIndex; // element index within parent
},
// Element dragging ended
onEnd: function (/**Event*/evt) {
var itemEl = evt.item; // dragged HTMLElement
evt.to; // target list
evt.from; // previous list
evt.oldIndex; // element's old index within old parent
evt.newIndex; // element's new index within new parent
evt.oldDraggableIndex; // element's old index within old parent, only counting draggable elements
evt.newDraggableIndex; // element's new index within new parent, only counting draggable elements
evt.clone // the clone element
evt.pullMode; // when item is in another sortable: `"clone"` if cloning, `true` if moving
},
// Element is dropped into the list from another list
onAdd: function (/**Event*/evt) {
// same properties as onEnd
},
// Changed sorting within list
onUpdate: function (/**Event*/evt) {
// same properties as onEnd
},
// Called by any change to the list (add / update / remove)
onSort: function (/**Event*/evt) {
// same properties as onEnd
},
// Element is removed from the list into another list
onRemove: function (/**Event*/evt) {
// same properties as onEnd
},
// Attempt to drag a filtered element
onFilter: function (/**Event*/evt) {
var itemEl = evt.item; // HTMLElement receiving the `mousedown|tapstart` event.
},
// Event when you move an item in the list or between lists
onMove: function (/**Event*/evt, /**Event*/originalEvent) {
// Example: https://jsbin.com/nawahef/edit?js,output
evt.dragged; // dragged HTMLElement
evt.draggedRect; // DOMRect {left, top, right, bottom}
evt.related; // HTMLElement on which have guided
evt.relatedRect; // DOMRect
evt.willInsertAfter; // Boolean that is true if Sortable will insert drag element after target by default
originalEvent.clientY; // mouse position
// return false; — for cancel
// return -1; — insert before target
// return 1; — insert after target
// return true; — keep default insertion point based on the direction
// return void; — keep default insertion point based on the direction
},
// Called when creating a clone of element
onClone: function (/**Event*/evt) {
var origEl = evt.item;
var cloneEl = evt.clone;
},
// Called when dragging element changes position
onChange: function(/**Event*/evt) {
evt.newIndex // most likely why this event is used is to get the dragging element's current index
// same properties as onEnd
}
});
group
选项要将元素从一个列表拖到另一个列表,两个列表必须具有相同的 group
值。
您还可以定义列表是否可以放弃、提供并保留副本(“clone”)以及接收元素。
String
— 组名称true|false|["foo", "bar"]|'clone'|function
— 是否可以从列表中移动。clone
— 复制项目,而不是移动。或者是一个可以放入元素的组名称数组。默认为 true
。true|false|["baz", "qux"]|function
— 是否可以从其他列表添加元素,或者是一个可以从中添加元素的组名称数组。boolean
— 移动到另一个列表后,将克隆的元素还原到初始位置。示例:
pull
和 put
中使用复杂的逻辑revertClone: true
sort
选项允许在列表内排序。
demo:https://jsbin.com/jayedig/edit?js,output
delay
选项以毫秒为单位,用于定义排序的开始时间。
遗憾的是,由于浏览器限制,在 IE 或 Edge 上无法使用原生拖放功能进行延迟。
演示:https://jsbin.com/zosiwah/edit?js,output
delayOnTouchOnly
选项是否仅在用户使用触摸操作时(例如在移动设备上)应用延迟。其他情况下均不应用延迟。默认为 false
。
swapThreshold
选项交换区域占目标的百分比,以介于 0
和 1
之间的浮点数表示。
演示:http://sortablejs.github.io/Sortable#thresholds
invertSwap
选项设置为 true
可将交换区域设置为目标的两侧,以实现对“中间”项目进行排序的效果。
演示:http://sortablejs.github.io/Sortable#thresholds
invertedSwapThreshold
选项反转交换区域占目标的百分比,以介于 0
和 1
之间的浮点数表示。如果未指定,则默认为 swapThreshold
。
direction
选项可排序元素的排序方向。可以设置为 'vertical'
、'horizontal'
或一个函数,该函数会在目标被拖拽时被调用。必须返回 'vertical'
或 'horizontal'
。
包含整列和半列元素的垂直列表方向检测示例:
Sortable.create(el, {
direction: function(evt, target, dragEl) {
if (target !== null && target.className.includes('half-column') && dragEl.className.includes('half-column')) {
return 'horizontal';
}
return 'vertical';
}
});
touchStartThreshold
选项此选项与 fallbackTolerance
选项类似。
设置 delay
选项后,某些配备高灵敏度触摸屏的手机(例如三星 Galaxy S8)即使手指未移动,也会触发
不必要的 touchmove 事件,导致排序无法触发。
此选项设置取消延迟排序之前必须发生的最小指针移动次数。
值最好在 3 到 5 之间。
disabled
选项如果设置为 true
,则禁用可排序功能。
演示:https://jsbin.com/sewokud/edit?js,output
var sortable = Sortable.create(list);
document.getElementById("switcher").onclick = function () {
var state = sortable.option("disabled"); // 获取
sortable.option("disabled", !state); // 设置
};
handle
选项为了使列表项可拖动,Sortable 会禁用用户的文本选择。
这并不总是可取的。为了允许文本选择,请定义一个拖动处理程序,
它是每个列表元素中允许拖动的区域。
演示:https://jsbin.com/numakuh/edit?html,js,output
Sortable.create(el, {
handle: ".my-handle"
});
<ul>
<li><span class="my-handle">::</span> 列表项文本一
<li><span class="my-handle">::</span> 列表项文本二
</ul>
.my-handle {
cursor: move;
cursor: -webkit-grabbing;
}
filter
选项Sortable.create(list, {
filter: ".js-remove, .js-edit",
onFilter: function (evt) {
var item = evt.item,
ctrl = evt.target;
if (Sortable.utils.is(ctrl, ".js-remove")) { // Click on remove button
item.parentNode.removeChild(item); // remove sortable item
}
else if (Sortable.utils.is(ctrl, ".js-edit")) { // Click on edit link
// ...
}
}
})
ghostClass
选项放置占位符的类名(默认为“sortable-ghost”)。
Demo: https://jsbin.com/henuyiw/edit?css,js,output
.ghost {
opacity: 0.4;
}
Sortable.create(list, {
ghostClass: "ghost"
});
chosenClass
选项所选项目的类名(默认为“sortable-chosen”)。
Demo: https://jsbin.com/hoqufox/edit?css,js,output
.chosen {
color: #fff;
background-color: #c00;
}
Sortable.create(list, {
delay: 500,
chosenClass: "chosen"
});
forceFallback
选项如果设置为 true
,即使我们使用的是 HTML5 浏览器,也会使用非 HTML5 浏览器的回退机制。
这使我们能够在较新的浏览器中测试旧版浏览器的行为,或者使拖放操作在桌面、移动和旧版浏览器之间感觉更加一致。
此外,回退机制始终会生成该 DOM 元素的副本,并附加在选项中定义的 fallbackClass
类。此行为控制此“拖动”元素的外观。
演示:https://jsbin.com/sibiput/edit?html,css,js,output
fallbackTolerance
选项模拟原生拖动阈值。以像素为单位指定鼠标移动多远才被视为拖动。
如果项目也可以点击,例如在链接列表中,则非常有用。
当用户在可排序元素内部点击时,从按下到释放之间手部略微移动是很常见的。
只有当指针移动超过一定容差时才会开始拖动,这样就不会每次点击时都意外开始拖动。
3 到 5 可能是比较合适的值。
dragoverBubble
选项如果设置为 true
,dragover 事件将冒泡到父级可排序元素。适用于回退事件和原生 dragover 事件。
默认情况下,该选项为 false,但只有当元素已插入父级可排序元素,或者可以插入父级可排序元素,但尚未插入(由于动画等原因)时,Sortable 才会停止冒泡事件。
从 1.8.0 开始,您可能希望将此选项保留为 false。在 1.8.0 之前,嵌套可排序元素可能需要设置为 true
才能正常工作。
removeCloneOnHide
选项如果设置为 false
,则克隆元素会通过将其 CSS display
属性设置为 none
来隐藏。
默认情况下,此选项为 true
,这意味着当克隆元素应该隐藏时,Sortable 会将其从 DOM 中移除。
emptyInsertThreshold
选项拖动时,鼠标与空的可排序元素之间的距离(以像素为单位),拖动元素才会插入到该可排序元素中。默认为 5
。设置为 0
可禁用此功能。
演示:https://jsbin.com/becavoj/edit?js,output
此选项的另一种方法是在列表为空时设置内边距。
例如:
ul:empty {
padding-bottom: 20px;
}
警告:要使 :empty
生效,它内部必须没有任何节点(即使是文本节点)。
演示:https://jsbin.com/yunakeg/edit?html,css,js,output
HTMLElement
— 移动元素所在的列表HTMLElement
— 上一个列表HTMLElement
— 被拖拽元素HTMLElement
Number|undefined
— 父元素中的旧索引Number|undefined
— 父元素中的新索引Number|undefined
— 父元素中的旧索引,仅计算可拖拽元素Number|undefined
— 父元素中的新索引,仅计算可拖拽元素String|Boolean|undefined
— 拖拽至另一个可排序元素时为拖拽模式 ("clone"
、true
或 false
),否则未定义move
事件对象HTMLElement
HTMLElement
HTMLElement
DOMRect
HTMLElement
— 已引导的元素DOMRect
Boolean
— 元素插入目标后,返回 true
(插入目标前,返回 false
)String
[, value:*
]):*
获取或设置选项。
HTMLElement
[, selector:String
]):HTMLElement|null
对于集合中的每个元素,通过测试元素本身并遍历其在 DOM 树中的祖先元素,获取第一个与选择器匹配的元素。
String[]
将可排序项的 data-id
(dataIdAttr
选项)序列化为字符串数组。
String[]
, useAnimation:Boolean
)根据数组对元素进行排序。
var order = sortable.toArray();
sortable.sort(order.reverse(), true); // 应用
保存当前排序(参见 store)
彻底移除可排序功能。
Saving and restoring of the sort.
<ul>
<li data-id="1">order</li>
<li data-id="2">save</li>
<li data-id="3">restore</li>
</ul>
Sortable.create(el, {
group: "localStorage-example",
store: {
/**
* Get the order of elements. Called once during initialization.
* @param {Sortable} sortable
* @returns {Array}
*/
get: function (sortable) {
var order = localStorage.getItem(sortable.options.group.name);
return order ? order.split('|') : [];
},
/**
* Save the order of elements. Called onEnd (when the item is dropped).
* @param {Sortable} sortable
*/
set: function (sortable) {
var order = sortable.toArray();
localStorage.setItem(sortable.options.group.name, order.join('|'));
}
}
})
Demo: https://jsbin.com/visimub/edit?html,js,output
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
<!-- Latest Sortable -->
<script src="http://SortableJS.github.io/Sortable/Sortable.js"></script>
<!-- Simple List -->
<ul id="simpleList" class="list-group">
<li class="list-group-item">This is <a href="http://SortableJS.github.io/Sortable/">Sortable</a></li>
<li class="list-group-item">It works with Bootstrap...</li>
<li class="list-group-item">...out of the box.</li>
<li class="list-group-item">It has support for touch devices.</li>
<li class="list-group-item">Just drag some elements around.</li>
</ul>
<script>
// Simple list
Sortable.create(simpleList, { /* options */ });
</script>
HTMLElement
[, options:Object
]):Sortable
创建新实例。
Sortable
活动的 Sortable 实例。
HTMLElement
被拖动的元素。
HTMLElement
幽灵元素。
HTMLElement
克隆元素。
HTMLElement
):Sortable
获取元素上的 Sortable 实例。
...SortablePlugin|SortablePlugin[]
)将插件挂载到 Sortable。
:HTMLElement
, event:String
, fn:Function
) — 附加事件处理函数:HTMLElement
, event:String
, fn:Function
) — 移除事件处理函数:HTMLElement
):Object
— 获取所有 CSS 属性的值:HTMLElement
, prop:String
):Mixed
— 获取样式属性的值:HTMLElement
, prop:String
, value:String
) — 设置一个 CSS 属性:HTMLElement
, props:Object
) — 设置更多 CSS 属性:HTMLElement
, tagName:String
[, iterator:Function
]):Array
— 通过标签名称获取元素:Mixed
, fn:Function
):Function
— 接受一个函数并返回一个始终具有特定上下文的新函数:HTMLElement
, selector:String
):Boolean
— 根据选择器检查当前匹配的元素集合:HTMLElement
, selector:String
[, ctx:HTMLElement
]):HTMLElement|Null
— 对于集合中的每个元素,通过测试元素本身并遍历其在 DOM 树中的祖先,获取第一个与选择器匹配的元素:HTMLElement
):HTMLElement
— 创建匹配元素集合的深层副本:HTMLElement
, name:String
, state:Boolean
) — 为每个元素添加或删除一个类:HTMLElement
):String
— 自动检测元素的 direction 方向,可以是 'vertical'
或 'horizontal'
:HTMLElement
, selector:String
):Number
— 元素在其父级中选定元素集合的索引:HTMLElement
, childNum:Number
, options:Object
, includeDragEl:Boolean
):HTMLElement
— 获取 Sortable 实例中指定索引处的可拖动元素:String
— 内部使用的 expando 属性名称,sortableListElement[expando] 返回该元素的 Sortable 实例<!-- jsDelivr :: Sortable :: Latest (https://www.jsdelivr.com/package/npm/sortablejs) -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
特此授予获得本软件及相关文档文件(以下简称“软件”)副本的任何人免费许可,以无限制方式处理本软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售本软件副本的权利,以及允许获得本软件的人员进行上述操作的权利,但须遵守以下条件:
上述版权声明和本许可声明应包含在软件的所有副本或重要部分中。
本软件“按原样”提供,不作任何形式的保证,无论明示或暗示,包括但不限于适销性、特定用途适用性和不侵权性的保证。在任何情况下,作者或版权持有人均不承担任何索赔、损害或其他责任,无论是合同诉讼、侵权诉讼还是其他诉讼,无论其是否因本软件、本软件的使用或其他交易而引起、产生或与之相关。