基于Vue快速实现列表拖拽排序

基于Vue快速实现列表拖拽排序在业务中列表拖拽排序是比较常见的需求,常见的JS拖拽库有Sortable.js,Vue.Draggable等,大多数同学遇到这种需求也是更多的求助于这些JS库,其实,使用HTML原生的拖放事件来实现拖拽排序并不复杂,结合Vue的transition-group,还能快速的给排序…

前言

在业务中列表拖拽排序是比较常见的需求,常见的JS拖拽库有Sortable.js,Vue.Draggable等,大多数同学遇到这种需求也是更多的求助于这些JS库,其实,使用HTML原生的拖放事件来实现拖拽排序并不复杂,结合Vue的transition-group,还能快速的给排序添加过渡动画。

demo

HTML5拖放API

设置元素为可拖放

让一个元素能被拖放需要设置 draggable 属性为true(文本、图片和链接的draggable默认就是true)

<div draggable="true">能被拖放的元素</div>

拖放事件

拖放涉及到两种元素,一种是被拖拽元素(源对象),一种是放置区元素(目标对象)。如下图所示,按住A元素往B元素拖拽,A元素即为源对象,B元素即为目标对象。

image-20201223092700804

不同的对象产生不同的拖放事件。

触发对象 事件名称 说明
源对象 dragstart 源对象开始被拖动时触发
drag 源对象被拖动过程中反复触发
dragend 源对象拖动结束时触发
目标对象 dragenter 源对象开始进入目标对象范围内触发
dragover 源对象在目标对象范围内移动时触发
dragleave 源对象离开目标对象范围时触发
drop 源对象在目标对象范围内被释放时触发

需要注意的是:dragenterdragover事件的默认行为是拒绝接受任何被拖放的元素。因此,我们要在这两个拖放事件中使用preventDefault来阻止浏览器的默认行为;而且目标对象想要变成可释放区域,必须设置dragoverdrop 事件处理程序属性。

拖放还有其他一些属性和方法,但对于我们今天要实现的效果,只需要掌握上面提到的这些属性和方法就可以了,如果你想深入探究,可以参考HTML拖放API

拖拽排序

下面我们利用拖放API来实现列表的拖拽排序,代码基于Vue实现。

先不考虑排序动画。代码并不复杂,就全部贴了出来,然后解释一下实现思路:

  1. 由于拖动是实时的,所以没有使用drop而是使用了dragenter触发排序。
  2. 在源对象开始被拖拽时记录其索引dragIndex,当它进入目标对象时(对应dragenter事件),将其插入到目标对象的位置。
  3. 其中dragenter方法中有一个判断this.dragIndex !== index(index为当前目标对象的索引),这是因为源对象同时也是目标对象,当没有这个判断时,源对象开始被拖拽时就会立刻触发自身的dragenter事件,这是不合理的。

最终效果如下图所示:

demo

<template>
  <ul class="list"> <li @dragenter="dragenter($event, index)" @dragover="dragover($event, index)" @dragstart="dragstart(index)" draggable v-for="(item, index) in list" :key="item.label" class="list-item" > {{item.label}} </li> </ul>
</template>
<script> export default { data() { return { list: [ { label: '列表1' }, { label: '列表2' }, { label: '列表3' }, { label: '列表4' }, { label: '列表5' }, { label: '列表6' }, ], dragIndex: '', enterIndex: '', }; }, methods: { dragstart(index) { this.dragIndex = index; }, dragenter(e, index) { e.preventDefault(); // 避免源对象触发自身的dragenter事件 if (this.dragIndex !== index) { const source = this.list[this.dragIndex]; this.list.splice(this.dragIndex, 1); this.list.splice(index, 0, source); // 排序变化后目标对象的索引变成源对象的索引 this.dragIndex = index; } }, dragover(e, index) { e.preventDefault(); }, }, }; </script>
<style lang="scss" scoped> .list { list-style: none; .list-item { cursor: move; width: 300px; background: #EA6E59; border-radius: 4px; color: #FFF; margin-bottom: 6px; height: 50px; line-height: 50px; text-align: center; } } </style>

减去HTML和CSS,核心的dragenter只有不超过15行的代码,就可实现一个拖拽排序功能。当然这个拖拽效果有点生硬,下面使用Vue自带的transition-group组件,给排序添加平滑的过渡效果。

排序动画

如果不熟悉Vue的transition-group,请先学习Vue的列表的排序过渡,这里不再赘述。

为了便于和上面的代码进行比较,同样一次性把全部代码贴出,可以看到代码变动并不大,只需把HTML的ul元素改为transition-group,在methods中新增shuffle方法,在CSS中新增一个过渡transition: transform .3s;即可实现开头第一张图所展示的拖拽排序效果了。

你可以点击此链接进行在线体验。

<template>
  <div> <transition-group name="drag" class="list" tag="ul" > <li @dragenter="dragenter($event, index)" @dragover="dragover($event, index)" @dragstart="dragstart(index)" draggable v-for="(item, index) in list" :key="item.label" class="list-item"> {{item.label}} </li> </transition-group> </div>
</template>
<script> export default { data() { return { list: [ { label: '列表1' }, { label: '列表2' }, { label: '列表3' }, { label: '列表4' }, { label: '列表5' }, { label: '列表6' }, ], dragIndex: '', enterIndex: '', }; }, methods: { shuffle() { this.list = this.$shuffle(this.list); }, dragstart(index) { this.dragIndex = index; }, dragenter(e, index) { e.preventDefault(); // 避免源对象触发自身的dragenter事件 if (this.dragIndex !== index) { const moving = this.list[this.dragIndex]; this.list.splice(this.dragIndex, 1); this.list.splice(index, 0, moving); // 排序变化后目标对象的索引变成源对象的索引 this.dragIndex = index; } }, dragover(e, index) { e.preventDefault(); }, }, }; </script>
<style lang="scss" scoped> .list { list-style: none; .drag-move { transition: transform .3s; } .list-item { cursor: move; width: 300px; background: #EA6E59; border-radius: 4px; color: #FFF; margin-bottom: 6px; height: 50px; line-height: 50px; text-align: center; } } </style>

如果想使用原生JS实现列表的拖拽排序和过渡动画,可以参考这篇文章:js drag拖动排序

今天的文章基于Vue快速实现列表拖拽排序分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/14640.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注