使用场景
获取数据循环生成列表,列表可以拖动设置列表排序。 如:
生成地图图层列表,拖动图层控制图层顺序,使用H5的drop来实现。
实现
判断层级关系通过sourceId和targetId判断的,sourceId是拖动Item的Id,targetId是你拖动放置位置下一个Item的Id。
如果拖动放置到最后位置的时候,由于没有Item了所以需要设置一个最后的Div当做foot。
实现代码思路
获取拖动Item的souce 和 索引,删除原始数组中的souce。查询targetId,获取targetId的索引, 在targetId前插入souce。
具体代码
Home.vue:
LayerItem:根据数据生成的Item div class="h60":最后设置为foot的Div
当被拖动Item放置在最后一位的时候触发
@drop.stop:拖动触动 @dragover:当被拖动元素在释放区内移动时触发 @dragleave:当被拖动元素没有放下就离开释放区时触发
<LayerItem :layer="layer"
v-for="layer in revertLayers"
:key="layer.index"
@on-move="moveLayer"
/>
<div class="h60" :class="{beforedrop: isDragOver}" @drop.stop.prevent="moveToBottom" @dragover="allowDrop" @dragleave="dragLeave"></div>
LayerItem.vue:
<div class="box" :class="{beforedrop: isDragOver}" @drop.stop.prevent="drop" @dragover="allowDrop" @dragleave="dragLeave">
<label :title="title" :draggable="true" @dragstart="dragStart">{{title}}</label>
</div>
全部代码: Home.vue
<template>
<div class="warp">
<LayerItem :layer="layer"
v-for="layer in revertLayers"
:key="layer.index"
@on-move="moveLayer"
/>
<div class="h60" :class="{beforedrop: isDragOver}" @drop.stop.prevent="moveToBottom" @dragover="allowDrop" @dragleave="dragLeave"></div>
</div>
</template>
<script>
import LayerItem from './LayerItem'
export default {
data() {
return {
isDragOver: false,
revertLayers:[{
id:"1",
value:"A"
},
{
id:"2",
value:"B"
},
{
id:"3",
value:"C"
},
{
id:"4",
value:"D"
},
{
id:"5",
value:"E"
}]
}
},
components: {
LayerItem
},
methods: {
allowDrop(e) {
this.isDragOver = true
e.preventDefault()
},
dragLeave() {
this.isDragOver = false
},
moveToBottom(e) {
this.isDragOver = false
let sourceId = e.dataTransfer.getData('layerId')
this.moveLayer({sourceId})
},
moveLayer(params) {
let {sourceId, targetId} = params
let sourcesIndex = this.revertLayers.findIndex(lay => lay.id === sourceId)
let sourcesLayer = this.revertLayers[sourcesIndex]
this.revertLayers.splice(sourcesIndex,1)
let targetIndex = this.revertLayers.findIndex(lyr => lyr.id === targetId)
if(targetId){
this.revertLayers.splice(targetIndex, 0, sourcesLayer)
} else {
this.revertLayers.push(sourcesLayer)
}
}
}
}
</script>
<style lang="less" scoped>
.h60{
height: 60px;
border-top: 2px solid transparent;
&.beforedrop{
border-top: 2px solid #8534b3;
}
}
.warp{
box-shadow:0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
padding-top: 80px;
}
</style>
LayerItem.vue
<template>
<div class="box" :class="{beforedrop: isDragOver}" @drop.stop.prevent="drop" @dragover="allowDrop" @dragleave="dragLeave">
<label :title="layer.value" class="layer" :draggable="true" @dragstart="dragStart">{{layer.value}}</label>
</div>
</template>
<script>
export default {
props:['layer'],
data () {
return {
isDragOver:false
}
},
methods: {
dragStart(e){
e.dataTransfer.setData('layerId', this.layer.id)
},
allowDrop(e) {
this.isDragOver = true
e.preventDefault()
},
dragLeave() {
this.isDragOver = false
},
drop(e) {
this.isDragOver = false
let layerId = e.dataTransfer.getData('layerId')
this.$emit('on-move', {sourceId: layerId, targetId: this.layer.id})
}
}
}
</script>
<style lang="less" scoped>
.box{
border: 1px solid #b0b5b8;
margin-bottom: 4px;
padding:4px 12px;
width: 230px;
margin-left: 10px;
border-radius: 3px;
cursor: pointer;
&.beforedrop{
border-top: 1px solid #0099ff;
}
label{
display: inline-block;
vertical-align: middle;
width: 100%;
word-break: keep-all;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
}
}
</style>