Sortable.js:功能强大的JavaScript 拖拽库

2024-01-08 22:36

本文主要是介绍Sortable.js:功能强大的JavaScript 拖拽库,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址:Sortable.js:功能强大的JavaScript 拖拽库

一、介绍

Sortable.js一个功能强大的JavaScript 拖拽库!!!用于在网页上创建可拖放和可排序的元素。它提供了简单而强大的 API,使开发人员能够轻松地实现拖放功能,并允许用户通过拖放来重新排序列表、网格和其他元素。

主要有以下特性:

  • 兼容性好:支持触屏设备和大部分浏览器,支持现代浏览器,并提供了对旧版浏览器的向后兼容性;
  • 简单:简单的API,方便使用,通过简单的HTML 结构和 JavaScript API,可以快速实现拖放排序功能;
  • 原生:基于原生HTML5中的拖放API;
  • CSS框架兼容性:支持所有的css框架,像Bootstrap;
  • 零依赖:不依赖Jquery等其他框架;
  • SPA支持良好:支持多种框架(angular、vue、react等);
  • 高度可定制:通过配置选项和回调函数,可以自定义拖放行为和排序效果;
  • 交互性:除了基本的拖放功能外,SortableJS 还提供了丰富的交互性选项,如拖放动画、排序同步等; 社区支持:
  • SortableJS有一个活跃的开发者社区,为使用该库的开发者提供支持、插件和示例。

二、安装

1、npm安装

npm install sortablejs --save

2、bower安装

bower install --save sortablejs

3、script引入

<script src="../../js/Sortable.min.js"></script>

三、配置项

const sortable = new Sortable(el, {// or { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }group: "name", // boolean 定义是否列表单元是否可以在列表容器内进行拖拽排序sort: true,  // number 定义鼠标选中列表单元可以开始拖动的延迟时间;delay: 0,// px,在取消延迟拖动事件之前,点应该移动多少像素touchStartThreshold: 0, // boolean 定义是否此sortable对象是否可用,为true时sortable对象不能拖放排序等功能,为false时为可以进行排序,相当于一个开关;disabled: false, // @see Storestore: null, // ms, number 单位:ms,定义排序动画的时间animation: 150, // 制作动画。默认为null,https://easings.net/。easing: "cubic-bezier(1, 0, 0, 1)",// 格式为简单css选择器的字符串,使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动handle: ".my-handle", // 过滤器,不需要进行拖动的元素filter: ".ignore-elements", //  在触发过滤器`filter`的时候调用`event.preventDefault()`preventOnFilter: true, // 允许拖拽的项目类名draggable: ".item", // drop placeholder的css类名ghostClass: "sortable-ghost", // 被选中项的css 类名chosenClass: "sortable-chosen", // 正在被拖拽中的css类名dragClass: "sortable-drag", dataIdAttr: 'data-id',// 交换区的阈值swapThreshold: 1,// 如果设置为 true,将始终使用反向交换区invertSwap: false, // 反向交换阈值,默认情况下将设置为swapThreshold 值invertedSwapThreshold: 1, // 拖拽方向 (默认情况下会自动判断方向)direction: 'horizontal', // 忽略 HTML5拖拽行为,强制回调进行forceFallback: false,  // 当使用forceFallback的时候,被复制的dom的css类名fallbackClass: "sortable-fallback",  // 将cloned DOM 元素挂到body元素上。fallbackOnBody: false,  // 以像素为单位指定鼠标在被视为拖动之前应移动的距离。fallbackTolerance: 0,// 是否启用滚动,值为true或者HTMLElementscroll: true,// 自定义滚动scrollFn: function(offsetX, offsetY, originalEvent, touchEvt, hoverTargetEl) { ... }, // 鼠标必须离边缘多近才能开始滚动,单位 pxscrollSensitivity: 30, // 滚动速度,pxscrollSpeed: 10,// 将自动滚动应用于所有父元素,以便更轻松地移动bubbleScroll: true, dragoverBubble: false,// 删除不显示的克隆元素,而不是仅仅隐藏它removeCloneOnHide: true, // 拖动时鼠标必须与空可排序项的距离(以像素为单位),以便将拖动元素插入到该可排序项中, 设置为0禁用此功能。emptyInsertThreshold: 5,setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {dataTransfer.setData('Text', dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent},// 元素被选中onChoose: function (/**Event*/evt) {evt.oldIndex;  // element index within parent},// 元素未被选中的时候(从选中到未选中)onUnchoose: function(/**Event*/evt) {// same properties as onEnd},// 开始拖拽的时候onStart: function (/**Event*/evt) {evt.oldIndex;  // element index within parent},// 结束拖拽onEnd: function (/**Event*/evt) {var itemEl = evt.item;  // dragged HTMLElementevt.to;    // target listevt.from;  // previous listevt.oldIndex;  // element's old index within old parentevt.newIndex;  // element's new index within new parentevt.clone // the clone elementevt.pullMode;  // when item is in another sortable: `"clone"` if cloning, `true` if moving},// 元素从一个列表拖拽到另一个列表onAdd: function (/**Event*/evt) {// same properties as onEnd},// 列表内元素顺序更新的时候触发onUpdate: function (/**Event*/evt) {// same properties as onEnd},// 列表的任何更改都会触发onSort: function (/**Event*/evt) {// same properties as onEnd},// 元素从列表中移除进入另一个列表onRemove: function (/**Event*/evt) {// same properties as onEnd},// 试图拖拽一个filtered的元素onFilter: function (/**Event*/evt) {var itemEl = evt.item;  // HTMLElement receiving the `mousedown|tapstart` event.},// 拖拽移动的时候onMove: function (/**Event*/evt, /**Event*/originalEvent) {// Example: https://jsbin.com/nawahef/edit?js,outputevt.dragged; // dragged HTMLElementevt.draggedRect; // DOMRect {left, top, right, bottom}evt.related; // HTMLElement on which have guidedevt.relatedRect; // DOMRectevt.willInsertAfter; // Boolean that is true if Sortable will insert drag element after target by defaultoriginalEvent.clientY; // mouse position// return false; — for cancel// return -1; — insert before target// return 1; — insert after target},// clone一个元素的时候触发onClone: function (/**Event*/evt) {var origEl = evt.item;var cloneEl = evt.clone;},// 拖拽元素改变位置的时候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}
});                    

1.属性

(1)group:string or object

  • string:命名,个人建议用元素id就行,用处是为了设置可以拖放容器时使用,在array中的put的设置中再做介绍。
  • object:{name,pull,put}。
    name:同string的方法。
    pull:pull用来定义从这个列表容器移动出去的设置,true/false/‘clone’/function。true:列表容器内的列表单元可以被移出;false:列表容器内的列表单元不可以被移出;‘clone’:列表单元移出,移动的为该元素的副本;function:用来进行pull的函数判断,可以进行复杂逻辑,在函数中return false/true来判断是否移出。
    put:put用来定义往这个列表容器放置列表单元的的设置,true/false/[‘foo’,‘bar’]/function。true:列表容器可以从其他列表容器内放入列表单元;false:与true相反; [‘foo’,‘bar’]:这个可以是一个字符串或者是字符串的数组,代表的是group配置项里定义的name值; function:用来进行put的函数判断,可以进行复杂逻辑,在函数中return false/true来判断是否放入。

(2)sort:boolean 定义是否列表单元是否可以在列表容器内进行拖拽排序;

(3)delay:number 定义鼠标选中列表单元可以开始拖动的延迟时间;

(4)disabled:boolean 定义是否此sortable对象是否可用,为true时sortable对象不能拖放排序等功能,为false时为可以进行排序,相当于一个开关;

(5)animation:number 单位:ms,定义排序动画的时间;

(6)handle:selector 格式为简单css选择器的字符串,使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动;

**(7)filter:**selector 格式为简单css选择器的字符串,定义哪些列表单元不能进行拖放,可设置为多个选择器,中间用“,”分隔;

(8)draggable:selector 格式为简单css选择器的字符串,定义哪些列表单元可以进行拖放

(9)ghostClass:selector 格式为简单css选择器的字符串,当拖动列表单元时会生成一个副本作为影子单元来模拟被拖动单元排序的情况,此配置项就是来给这个影子单元添加一个class,我们可以通过这种方式来给影子元素进行编辑样式;

(10)chosenClass:selector 格式为简单css选择器的字符串,当选中列表单元时会给该单元增加一个class;

(11)forceFallback:boolean 如果设置为true时,将不使用原生的html5的拖放,可以修改一些拖放中元素的样式等;

(12)fallbackClass:string 当forceFallback设置为true时,拖放过程中鼠标附着单元的样式;

(13)scroll:boolean 默认为true,当排序的容器是个可滚动的区域,拖放可以引起区域滚动。

2.事件

onChoose:function 列表单元被选中的回调函数

onStart:function 列表单元拖动开始的回调函数

onEnd:function 列表单元拖放结束后的回调函数

onAdd:function 列表单元添加到本列表容器的回调函数

onUpdate:function 列表单元在列表容器中的排序发生变化后的回调函数

onRemove:function 列表元素移到另一个列表容器的回调函数

onFilter:function 试图选中一个被filter过滤的列表单元的回调函数

onMove:function 当移动列表单元在一个列表容器中或者多个列表容器中的回调函数

onClone:function 当创建一个列表单元副本的时候的回调函数

3.事件对象

事件对象在各个函数中略有不同,可通过输出对象查看对象的属性,下面简单列举几个:

to:HTMLElement–移动到列表容器

from:HTMLElement–来源的列表容器

item:HTMLElement–被移动的列表单元

clone:HTMLElement–副本的列表单元

oldIndex:number/undefined–在列表容器中的原序号

newIndex:number/undefined–在列表容器中的新序号

4.方法

option(name[,value])
获得或者设置项参数,使用方法类似于jQuery用法,没有第二个参数为获得option中第一个参数所对应的值,有第二个参数时,将重新赋给第一个参数所对应的值;

closest
没理解

toArray()
序列化可排序的列表单元的data-id(可通过配置项中dataIdAttr修改)放入一个数组,并返回这个数组中

sort()
通过自定义列表单元的data-id的数组对列表单元进行排序

save()
destroy()

四、实战应用

1.Vue先把数据渲染到页面上;

2.利用sortablejs操作真实dom,得到列表,sortablejs 核心就是操作真实dom,这时候由于vue本身数据未更新,所以也不会触发dom的重新渲染,这就导致了vue里面的数据与真实dom的数据是对不上的,所以有了第3步;

3.利用sortablejs的onEnd方法把数据变化映射到真实的vue的数据源list上,实现拖拽时dom变化是对应的。

环境如下:
在这里插入图片描述

1、简单列表拖拽

<script setup lang="ts">
import Sortable from 'sortablejs'
import { ref, onMounted, nextTick } from 'vue';const sortableRef = ref(null)
const list = [{name: 'item1'},{name: 'item2'},{name: 'item3'},{name: 'item4'},{name: 'item5'},{name: 'item6'}
]const initSortable = () => {new Sortable(sortableRef.value, {delay: 10,animation: 150,// 如果有不想排序的,在这里按照class匹配的方式写出即可filter: '.demo-title',// 需要拖拽的标签的class,强烈推荐写draggable: '.demo-item',// drop placeholder的css类名ghostClass: 'blue-background-class'});
}onMounted(() => {nextTick(() => {initSortable()})
})
</script><template><ul ref="sortableRef" class="demo"><li class="demo-title">Demo</li><li class="demo-item" v-for="item in list" :key="item.name">{{ item.name }}</li></ul>
</template><style lang="scss" scoped>
.demo {list-style: none;width: 40%;margin: 200px auto 0;.demo-title {text-align: center;font-weight: 600;font-size: 16px;}.demo-item {border: 1px solid red;margin: 10px 0;padding: 10px 0;text-align: center;}
}
.blue-background-class {background-color: #1890ff;
}
</style>

效果如下:
在这里插入图片描述

2、多列表相互拖拽

<script setup lang="ts">
import Sortable from 'sortablejs'
import { ref, onMounted, nextTick } from 'vue';const demo1Ref = ref(null)
const demo2Ref = ref(null)const initSortable = () => {new Sortable(demo1Ref.value, {// 相互拖拽列表的组名必须一样group: 'shared',delay: 10,animation: 150,// 需要拖拽的标签的class,强烈推荐写// 拖拽元素的类名一样,否则其它列表拖过来的不能在当前列表拖动draggable: '.demo-item'});new Sortable(demo2Ref.value, {// 相互拖拽列表的组名必须一样group: 'shared',delay: 10,animation: 150,// 需要拖拽的标签的class,强烈推荐写// 拖拽元素的类名一样,否则其它列表拖过来的不能在当前列表拖动draggable: '.demo-item'});
}onMounted(() => {nextTick(() => {initSortable()})
})
</script><template><div class="demo-container"><ul ref="demo1Ref" class="demo"><li class="demo-item demo1-item" v-for="item in 6" :key="'demo1'+item">item{{ item }}</li></ul><ul ref="demo2Ref" class="demo"><li class="demo-item demo2-item" v-for="item in 6" :key="'demo2'+item">item{{ item }}</li></ul></div>
</template><style lang="scss" scoped>
.demo-container {display: flex;justify-content: space-between;width: 1000px;.demo {list-style: none;width: 48%;.demo-item {margin: 10px 0;padding: 10px 0;text-align: center;}.demo1-item {background-color: #5ac8fa;}.demo2-item {background-color: #c0ca33;}}
}
</style>        

效果如下:
图片

3、克隆(通过拖拽复制节点)

new Sortable(demo1Ref.value, {group: {name: 'shared',pull: 'clone' // To clone: set pull to 'clone'},delay: 10,animation: 150,// 需要拖拽的标签的class,强烈推荐写// 拖拽元素的类名一样,否则其它列表拖过来的不能在当前列表拖动draggable: '.demo-item'
});new Sortable(demo2Ref.value, {group: {name: 'shared',pull: 'clone' // To clone: set pull to 'clone'},delay: 10,animation: 150,// 需要拖拽的标签的class,强烈推荐写// 拖拽元素的类名一样,否则其它列表拖过来的不能在当前列表拖动draggable: '.demo-item'
});

效果如下:

图片
4、禁止sorting

坐标的列表无法进行排序,因为设置了禁止sort,但是你还是可以从左边拖拽到右边。

new Sortable(demo1Ref.value, {group: {name: 'shared',pull: 'clone',put: false // 不允许拖拽进这个列表},sort: false, // 设为false,禁止sortdelay: 10,animation: 150,// 需要拖拽的标签的class,强烈推荐写// 拖拽元素的类名一样,否则其它列表拖过来的不能在当前列表拖动draggable: '.demo-item'
});new Sortable(demo2Ref.value, {group: 'shared',delay: 10,animation: 150,// 需要拖拽的标签的class,强烈推荐写// 拖拽元素的类名一样,否则其它列表拖过来的不能在当前列表拖动draggable: '.demo-item'
});

效果如下:

在这里插入图片描述

5、Handle

使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动。在面代码中只有按住白色方块才能拖动元素。

<script setup lang="ts">
import Sortable from 'sortablejs'
import { ref, onMounted, nextTick } from 'vue';const sortableRef = ref(null)const initSortable = () => {new Sortable(sortableRef.value, {handle: '.handle-draggabel',animation: 150,});
}onMounted(() => {nextTick(() => {initSortable()})
})
</script><template><ul ref="sortableRef" class="demo"><li class="demo-item" v-for="item in 6" :key="item"><span class="handle-draggabel"></span><span>item{{ item }}</span></li></ul>
</template><style lang="scss" scoped>
.demo {list-style: none;width: 40%;.demo-item {background-color: #1890ff;margin: 10px 0;padding: 10px 0;color: #fff;text-align: center;.handle-draggabel {display: inline-block;width: 14px;height: 14px;background-color: #fff;margin-right: 10px;cursor: pointer;}}
}
</style>

效果如下:

图片

五、总结

除了基本的拖放功能外,SortableJS 还提供了许多额外的功能和选项,例如拖放动画、排序同步、多选模式等。这些功能可以帮助您创建更加丰富和用户友好的交互体验。

SortableJS 的社区非常活跃,许多开发者使用该库并为其贡献插件和示例。这意味着您可以找到许多现成的解决方案和资源,以帮助您解决在开发中遇到的问题。

总的来说,SortableJS 是一个强大、灵活且易于使用的 JavaScript 库,适用于各种类型的拖放排序需求。无论是简单的列表排序还是复杂的交互式应用程序,SortableJS 都能够帮助您快速实现所需的功能。如果您正在寻找一个可靠的拖放库来增强您的网页或应用程序的交互性,SortableJS 是一个值得考虑的选择。

文档地址:http://www.sortablejs.com/index.html

这篇关于Sortable.js:功能强大的JavaScript 拖拽库的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/585073

相关文章

Java中对象的创建和销毁过程详析

《Java中对象的创建和销毁过程详析》:本文主要介绍Java中对象的创建和销毁过程,对象的创建过程包括类加载检查、内存分配、初始化零值内存、设置对象头和执行init方法,对象的销毁过程由垃圾回收机... 目录前言对象的创建过程1. 类加载检查2China编程. 分配内存3. 初始化零值4. 设置对象头5. 执行

SpringBoot整合easy-es的详细过程

《SpringBoot整合easy-es的详细过程》本文介绍了EasyES,一个基于Elasticsearch的ORM框架,旨在简化开发流程并提高效率,EasyES支持SpringBoot框架,并提供... 目录一、easy-es简介二、实现基于Spring Boot框架的应用程序代码1.添加相关依赖2.添

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程

《SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程》本文详细介绍了如何在虚拟机和宝塔面板中安装RabbitMQ,并使用Java代码实现消息的发送和接收,通过异步通讯,可以优化... 目录一、RabbitMQ安装二、启动RabbitMQ三、javascript编写Java代码1、引入

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在