写在前面
在业务中列表拖拽排序是比较常见的需求,常见的JS拖拽库有Sortable.js,Vue.Draggable等,大多数同学遇到这种需求也是更多的求助于这些JS库,其实,使用HTML原生的拖放事件来实现拖拽排序并不复杂,结合Vue的transition-group,还能快速的给排序添加过渡动画。
设置元素为可拖放
<div draggable="true">能被拖放的元素</div>
拖放事件
拖放涉及到两种元素,一种是被拖拽元素(源对象),一种是放置区元素(目标对象)。
按住A元素往B元素拖拽,A元素即为源对象,B元素即为目标对象
拖拽事件类型
触发对象 | 事件名称 | 说明 |
---|---|---|
源对象 | dragstart | 源对象开始被拖动时触发 |
源对象 | drag | 源对象被拖动过程中反复触发 |
源对象 | dragend | 源对象拖动结束时触发= |
目标对象 | dragenter | 源对象开始进入目标对象范围内触发 |
目标对象 | dragover | 源对象在目标对象范围内移动时触发 |
目标对象 | dragleave | 源对象离开目标对象范围时触发 |
目标对象 | drop | 源对象在目标对象范围内被释放时触发 |
拖拽排序
<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>
**当然这个拖拽效果有点生硬,下面使用Vue自带的transition-group组件,给排序添加平滑的过渡效果。
**
列表的排序过渡 (transition-group)
Vue的列表的: 排序过渡
<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>