sortablejs(前端拖拽排序的实现)

打印 上一主题 下一主题

主题 1831|帖子 1831|积分 5493

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
源文档:sortablejs - npm
安装
  1. npm install sortablejs --save
复制代码
引入项目
  1. import Sortable from 'sortablejs';
复制代码
利用示例
  1. <template>
  2.     <ul id="items">
  3.            <li>item 1</li>
  4.            <li>item 2</li>
  5.            <li>item 3</li>
  6.     </ul>
  7. </template>
  8. <script setup>
  9. import Sortable from 'sortablejs';
  10. const el = document.getElementById('items');
  11. const sortable = Sortable.create(el);
  12. </script>
  13. <style scoped lang="scss">
  14. </style>
复制代码
sortablejs的配置项
  1. const sortable = new Sortable(el, {
  2.         group: "name",  // or { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }
  3.         sort: true,  //是否可以在列表内排序,默认开启
  4.         delay: 0, //拖拽延迟时间(通常用于移动端实现长按拖拽)
  5.         delayOnTouchOnly: false, //只有当用户使用触摸时才会延迟
  6.         touchStartThreshold: 0, // 在取消延迟拖动事件之前,应该移动多少像素(px)
  7.         disabled: false, //如果设置为true,则禁用可排序。
  8.         store: null,  // @see Store
  9.         animation: 150,  // ms,排序时移动项目的动画速度,设置0则无过渡动画
  10.         easing: "cubic-bezier(1, 0, 0, 1)", //渐变动画,默认为null,可访问https://easings.net/查看示例
  11.         handle: ".my-handle",  // 需要绑定的元素(比如我们想长按某个盒子来拖拽其父元素,那么此时我们仅需要给这个盒子添加这里配置的类型即可)
  12.         filter: ".ignore-elements",  //不需要进行拖动的元素(给元素添加这个选项配置的类名后,该元素将不会被拖动)
  13.         preventOnFilter: true, // 当触发filter时调用event.preventDefault()
  14.         draggable: ".item",  // 指定元素内的哪些项可以被拖动
  15.         dataIdAttr: 'data-id', // HTML attribute that is used by the `toArray()` method
  16.         ghostClass: "sortable-ghost",  //占位元素类名,可以对此类名进行配置以实现特定效果(拖拽时,sortablejs会生成一个占位元素占据元素的位置,此类名主要用于控制这个元素的样式)
  17.         chosenClass: "sortable-chosen",  //所选项目的类名
  18.         dragClass: "sortable-drag",  //拖动项的类名
  19.         swapThreshold: 1, //交换区阈值
  20.         invertSwap: false, //如果设置为true,将始终使用反向交换区
  21.         invertedSwapThreshold: 1, //反转交换区的阈值(默认设置为swapThreshold值)
  22.         direction: 'horizontal', // 可分拣方向(如果没有给出,将自动检测)
  23.         forceFallback: false,  //忽略HTML5 行为并强制回退
  24.         fallbackClass: "sortable-fallback",  //使用forceFallback时克隆的DOM元素的类名
  25.         fallbackOnBody: false,  //将克隆的DOM元素附加到文档正文中
  26.         fallbackTolerance: 0, //以像素为单位指定鼠标在被视为拖动之前应该移动多远。
  27.         dragoverBubble: false,//拖拽经过时是否冒泡
  28.         removeCloneOnHide: true, //当clone元素未显示时将其删除,而不是将其隐藏
  29.         emptyInsertThreshold: 5, //px,鼠标距离必须为空可排序,才能将拖动元素插入其中
  30.         setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {
  31.                 dataTransfer.setData('Text', dragEl.textContent); //HTML5 DragEvent的DataTransfer对象
  32.         },
  33.         //元素被选中时触发
  34.         onChoose: function (/**Event*/evt) {
  35.                 evt.oldIndex;  //当前元素在父元素中的索引
  36.         },
  37.         //元素未被选中时(与onEnd事件相似)
  38.         onUnchoose: function(/**Event*/evt) {
  39.                 // same properties as onEnd
  40.         },
  41.         //开始拖拽时
  42.         onStart: function (/**Event*/evt) {
  43.                 evt.oldIndex;  //当前元素在父元素中的索引
  44.         },
  45.         //拖拽完成时
  46.         onEnd: function (/**Event*/evt) {
  47.                 var itemEl = evt.item;  //被拖拽的元素
  48.                 evt.to;    //目标列表
  49.                 evt.from;  //初始列表
  50.                 evt.oldIndex;  //初始列表的初始索引(即拖拽改变之前的列表索引)
  51.                 evt.newIndex;  //元素在新父级中的新索引(即拖拽之后形成的列表的索引)
  52.                 evt.oldDraggableIndex; //元素在旧父元素内的旧索引,仅计算可拖动元素                 
  53.         evt.newDraggableIndex; //元素在新父级中的新索引,仅计算可拖动元素
  54.                 evt.clone //克隆元素               
  55.         evt.pullMode;  //当项目位于另一个可排序的位置时:如果是克隆,则为“clone”;如果是移
  56.         动,则为true
  57.         //元素从另一个列表中删除到列表中
  58.         onAdd: function (/**Event*/evt) {
  59.                 //与onEnd具有相同的属性
  60.         },
  61.         //更改列表中的排序
  62.         onUpdate: function (/**Event*/evt) {
  63.                 //与onEnd具有相同的属性
  64.         },
  65.         //由列表的任何更改调用(添加/更新/删除)
  66.         onSort: function (/**Event*/evt) {
  67.                 //与onEnd具有相同的属性
  68.         },
  69.         //元素从列表中删除到另一个列表中
  70.         onRemove: function (/**Event*/evt) {
  71.                 //与onEnd具有相同的属性
  72.         },
  73.         //尝试拖动已过滤的元素
  74.         onFilter: function (/**Event*/evt) {
  75.                 var itemEl = evt.item;  //HTMLElement接收到“mousedown”、“tapstart”事件。
  76.         },
  77.         //在列表中或列表之间移动项目的事件
  78.         onMove: function (/**Event*/evt, /**Event*/originalEvent) {
  79.                 // Example: https://jsbin.com/nawahef/edit?js,output
  80.                 evt.dragged; // 被拖动元素
  81.                 evt.draggedRect; // DOMRect {left, top, right, bottom}
  82.                 evt.related; // HTMLElement on which have guided
  83.                 evt.relatedRect; // DOMRect
  84.                 evt.willInsertAfter; //布尔值,默认为真。为真的情况下Sortable将在目标后插入拖动元素
  85.                 originalEvent.clientY; //鼠标位置
  86.                 // return false; — for cancel
  87.                 // return -1; — 在目标之前插入
  88.                 // return 1; — 在目标之后插入
  89.                 // return true; —根据方向保留默认插入点
  90.                 // return void; —根据方向保留默认插入点
  91.         },
  92.         //创建元素克隆时调用
  93.         onClone: function (/**Event*/evt) {
  94.                 var origEl = evt.item;
  95.                 var cloneEl = evt.clone;
  96.         },
  97.         //当拖动元素改变位置时调用
  98.         onChange: function(/**Event*/evt) {
  99.                 evt.newIndex //使用此事件的最可能原因是获取拖动元素的当前索引
  100.                 // same properties as onEnd
  101.         }
  102. });
复制代码
vue3中的利用演示
  1. <template>
  2.   <div class="home">
  3.      <ul ref="boxRef" >
  4.          <li v-for="item in list"  :key="item.id" >
  5.             <div class="bread">
  6.                 <van-icon name="wap-nav" size="30px"  ></van-icon>
  7.             </div>  
  8.             <span> {{ item.text }}</span>
  9.          </li>
  10.      </ul>
  11.   </div>
  12. </template>
  13. <script setup>
  14. import { ref,onMounted } from 'vue';
  15. import Sortable from 'sortablejs';
  16. //sortable实例
  17. const instance = ref(null)
  18. const list = ref([
  19.   {
  20.     text: '张三',
  21.     id: 1,
  22.   },
  23.   {
  24.     text: '李四',
  25.     id: 2,
  26.   },
  27.   {
  28.     text: '王五',
  29.     id: 3,
  30.   },
  31.   {
  32.     text: '赵四',
  33.     id: 4,
  34.   },
  35.   {
  36.     text: '王大麻子',
  37.     id: 5,
  38.   },
  39. ]);
  40. //获取容器dom元素
  41. const boxRef = ref(null)
  42. onMounted(()=>{
  43.   instance.value = Sortable.create(boxRef.value,{
  44.          handle:'.bread', //设置了此类名,只有长按有这个类名的元素才能拖动(注意这里要带上选择器符号)
  45.          delay:600, //延迟600毫秒才能拖动
  46.          chosenClass:"move" //可以拖动时,被拖动项的类名
  47.   })
  48. })
  49. </script>
  50. <style scoped lang="less">
  51. .move{
  52.   background: orange;
  53. }
  54. .box {
  55.   margin: 20px auto;
  56.   width: 600px;
  57.   height: 600px;
  58.   box-shadow: 0 0 3px 5px #ccc;
  59. }
  60. ul{
  61.   margin:10px auto;
  62.   width:600px;
  63.   li{
  64.     margin:10px 0;
  65.     display: flex;
  66.     align-items: center;
  67.     height:80px;
  68.     line-height: 80px;
  69.     text-align: center;
  70.     background:#ccc;
  71.     .bread{
  72.       margin: 0 20px;
  73.       display: flex;
  74.       align-items: center;
  75.       width:50px;
  76.       height:50px;
  77.     }
  78.   }
  79. }
  80. </style>
复制代码
在实际的利用中我们通常利用sortablejs做拖拽排序,这就会涉及到异步请求及请求发送失败的情况。那么就会发现一个题目,当我们的请求发送失败后按照常理应该还原排序但是sortablejs似乎并没有给予相应的方法来实现这个功能。我们可以如下操作:
  1. <template>
  2.   <div class="home">
  3.     <ul ref="boxRef" @sort="onSort">
  4.       <li v-for="item in list" :key="item.id">
  5.         <div class="bread">
  6.           <van-icon name="wap-nav" size="30px"></van-icon>
  7.         </div>
  8.         <span> {{ item.text }}</span>
  9.       </li>
  10.     </ul>
  11.   </div>
  12. </template>
  13. <script setup >
  14. import { ref, onMounted } from 'vue';
  15. import Sortable from 'sortablejs';
  16. //获取容器dom元素
  17. const boxRef = ref(null);
  18. const list = ref([
  19.   {
  20.     text: '张三',
  21.     id: 1,
  22.   },
  23.   {
  24.     text: '李四',
  25.     id: 2,
  26.   },
  27.   {
  28.     text: '王五',
  29.     id: 3,
  30.   },
  31.   {
  32.     text: '赵四',
  33.     id: 4,
  34.   },
  35.   {
  36.     text: '王大麻子',
  37.     id: 5,
  38.   },
  39. ]);
  40. //sortable实例
  41. const instance = ref(null);
  42. //排序时触发的回调函数
  43. const onSort = async (value) => {
  44.   const { oldIndex, newIndex, from } = value;
  45.   try {
  46.     //模拟的异步请求失败情况
  47.     await new Promise((resolve, reject) => {
  48.       reject(new Error('发送错误'));
  49.     });
  50.   } catch (error) {
  51.     //请求失败时还原排序
  52.     const List = Array.from(from.children);
  53.     const item = List.splice(newIndex, 1)[0];
  54.     if (oldIndex > newIndex) {
  55.       from.insertBefore(item, List[oldIndex + 1]);
  56.     } else {
  57.       from.insertBefore(item, List[oldIndex]);
  58.     }
  59.   }
  60. };
  61. onMounted(() => {
  62.   //初始化sortablejs实例
  63.   instance.value = Sortable.create(boxRef.value, {
  64.     handle: '.bread', //设置了此类名,只有长按有这个类名的元素才能拖动(注意这里要带上选择器符号)
  65.     //  delay:600, //延迟600毫秒才能拖动
  66.     chosenClass: 'move', //可以拖动时,被拖动项的类名(可以自定义样式)
  67.   });
  68. });
  69. </script>
  70. <style scoped lang="less">
  71. .move {
  72.   background: orange;
  73. }
  74. .box {
  75.   margin: 20px auto;
  76.   width: 600px;
  77.   height: 600px;
  78.   box-shadow: 0 0 3px 5px #ccc;
  79. }
  80. ul {
  81.   margin: 10px auto;
  82.   width: 600px;
  83.   li {
  84.     margin: 10px 0;
  85.     display: flex;
  86.     align-items: center;
  87.     height: 80px;
  88.     line-height: 80px;
  89.     text-align: center;
  90.     background: #ccc;
  91.     .bread {
  92.       margin: 0 20px;
  93.       display: flex;
  94.       align-items: center;
  95.       width: 50px;
  96.       height: 50px;
  97.     }
  98.   }
  99. }
  100. </style>
复制代码
这样就可以实现一样寻常的工作需求,考虑到每次写这么多东西会很贫苦,我们可以利用vue的自定义指令将它封装成一个指令。现在已经有插件完成了这一步调,各人也可以实验一下这个插件。
传送门:vue3-sortablejs - npm

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天空闲话

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表