拖拽介绍:
目标是将左侧list中的item拖入右侧card中,如下所示:(将list1和list3拖入右侧拖拽区)
一、拖拽样式实现
使用vue + vuetifyjs实现。页面布局可根据不同的UI库自行修改。
html内容:
<template>
<div>
<h1 class="title">欢迎来到小余的梦幻王国~</h1>
<div class="d-flex justify-center ">
<v-card
class="mx-auto"
width="500"
>
<v-list dense>
<v-subheader>拖拽实现插入</v-subheader>
<v-list-item-group
v-model="selectedItem"
color="primary"
>
<v-list-item
v-for="(item, i) in list"
:key="i"
>
<v-list-item-title v-text="item"></v-list-item-title>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
<v-card
id="target"
width="500"
>
我是card
<div v-for="(item,i) in drapItem" :key="i">{{item}}</div>
</v-card>
</div>
</div>
</template>
js部分:
<script>
export default {
data() {
return {
list: ['list1', 'list2', 'list3', 'list4'],
selectedItem: 0,
drapItem: [],
};
},
};
</script>
二、拖拽事件
2.1 使元素可被拖拽
在要拖拽的元素上加入draggable="true"属性
<v-list-item
v-for="(item, i) in list"
:key="i"
draggable="true"
>
<v-list-item-title v-text="item"></v-list-item-title>
</v-list-item>
2.2 拖拽事件介绍
- @dragstart:拖拽开始事件,可绑定于被拖拽元素上(拖拽源);
- @dragend:拖拽结束事件,可绑定于被拖拽元素上(拖拽源);
- @dragover:拖拽持续移动事件,建议绑定于可拖放区域(右侧拖拽区);
- @dragenter:进入拖放区域,建议绑定于可拖放区域(右侧拖拽区),该事件仅在进入拖放区域时触发,在其内部移动时不触发,离开某一可拖放区域后再进入时会再次触发;
ondrop事件:
拖放事件,绑定于可拖放区域上。
<div
id="target"
width="500"
@drop="targetDrop"
>
目标拖拽区
</div>
然而当我们将可拖拽元素拖放至此时,并没有触发事件。
根据 MDN 的文档:
A listener for the dragenter and dragover events are used to indicate valid drop targets, that is, places where dragged items may be dropped. Most areas of a web page or application are not valid places to drop data. Thus, the default handling for these events is to not allow a drop.", hence the only way for the drop event to be fired is to first cancel the dragenter or dragover event.
我们必须阻止某一 DOM 元素对 dragover 的默认行为,才能使 drop 事件在其上正确执行。
<div class="drop-field"
@drop="drop"
@dragover.prevent
>
...
</div>
2.3 DataTransfer (传递消息)
DataTransfer 对象用于保存拖动并放下(drag and drop)过程中的数据。它可以保存一项或多项数据,这些数据项可以是一种或者多种数据类型。关于拖放的更多信息,请参见 Drag and Drop.
这个对象可以从所有拖动事件 drag events 的 dataTransfer 属性上获取。
2.3.1 DataTransfer 标准方法:
2.3.2 DataTransfer.setData 传递消息和传参
具体使用方法如下所示:
<v-list-item
v-for="(item, i) in list"
:key="i"
draggable="true"
@dragstart="dragstart($event, item,i)"
>
<v-list-item-title v-text="item"></v-list-item-title>
</v-list-item>
dragstart(e, item, index) {
// 参数e为DragEvent事件
e.dataTransfer.setData('item', item);
e.dataTransfer.setData('index', index);
},
2.3.3 在拖放区的 drop 事件中获取消息
<v-card
id="target"
width="500"
@dragover.prevent
@drop="targetDrop"
>
我是card
<div v-for="(item,i) in drapItem" :key="i">{{item}}</div>
</v-card>
targetDrop(e) {
const index = e.dataTransfer.getData('index');
// 增加数据
this.drapItem.push(e.dataTransfer.getData('item'));
// 删除原数据
this.list.splice(index, 1);
},
2.3.4 在拖拽对象(源)的 dragend 事件中清除消息
但其实清不清除事件好像都一样。。。
<v-list-item
v-for="(item, i) in list"
:key="i"
draggable="true"
@dragstart="dragstart($event, item,i)"
@dragend="dragend"
>
<v-list-item-title v-text="item"></v-list-item-title>
</v-list-item>
dragend(event) {
event.dataTransfer.clearData();
},
拖拽实现整体思路如下:
参考:
1.https://segmentfault.com/a/1190000013606983 作者是“dailybird”的文章。
2.mdn中的DataTransfer文章