参考
功能
代码
<template>
<div class="drag">
<el-container>
<el-aside width="300px">
<!-- 左边待选菜单区域 -->
<ul>
<li v-for="item in tags" :key="item">
<img
src="@/assets/image/dengjihang.png"
@dragstart="dragStart"
draggable="true"
:id="item"
@dragend="dragEnd"
@drag="ondrag"
/>
</li>
</ul>
</el-aside>
<el-main>
<!-- 自由移动区域 -->
<div @drop.prevent="drop" @dragover.prevent ref="moveArea" class="move-area">
<img
src="@/assets/image/dengjihang.png"
class="msg1"
:style="{left:info.x+'px',top:info.y+'px'}"
v-for="(info, index) in InfoList"
:key="index"
draggable="true"
@dragstart="imgStart"
@drag="imgDragging($event, info)"
@dragend="dragEnd"
/>
</div>
</el-main>
</el-container>
</div>
</template>
html中在设置了ondragover
监听事件的div区域上可接收drag的目标元素,否则是不可接收
<script>
// 该div在整个页面上,距离左上角的位置
const offTop = 40
const offLeft = 0
export default {
data() {
return {
tags: [1, 2, 3],
InfoList: [],
}
},
methods: {
dragStart(ev) {
console.log('dragstart拖拽开始事件,绑定于被拖拽元素上', ev)
let info = { id: ev.target.id, isDrop: true }
ev.dataTransfer.setData('Text', JSON.stringify(info))
// 鼠标相对于被选中元素的位置
this.offsetX = ev.offsetX
this.offsetY = ev.offsetY
console.log(this.offsetX + '-' + this.offsetY)
},
dragEnd(event) {
console.log('done')
event.dataTransfer.clearData()
},
/*
只有从左边拖入右边,需要在右边区域内新加一个img,并处理位置
否则就是拖动的区域内的img,不需要新加, 位置的改变交由imgDragging处理
*/
drop(e) {
let info = JSON.parse(e.dataTransfer.getData('Text'))
if (info.isDrop) {
info.x = e.clientX - this.offsetX - offLeft
info.y = e.clientY - this.offsetY - offTop
// 加时间戳,构造新id
info.id = info.id + Date.parse(new Date())
this.InfoList.push(info)
}
},
imgStart(e) {
// 区域内的拖动不需要执行drop事件, 所以设置false
let info = { isDrop: false }
e.dataTransfer.setData('Text', JSON.stringify(info))
this.imgOffsetX = e.offsetX
this.imgOffsetY = e.offsetY
},
imgDragging(e, item) {
item.x = e.clientX - this.imgOffsetX - offLeft
item.y = e.clientY - this.imgOffsetY - offTop
//console.log(e.clientX, e.clientY)
},
// 这个事件对功能不影响,可以不监听
ondrag(e) {
console.log(e.clientX, '---', e.clientY)
},
},
}
</script>
<style>
.drag{
position: relative;
}
.el-container{
height: 800px;
}
.el-aside {
width:300px;
background: rgb(252, 226, 226);
}
.el-main {
background: #cff9dc3b;
}
.move-area{
height:100%;
width:100%;
}
.msg1{
position: absolute;
}
</style>
改进
上面的代码存在一个问题,就是拖到右边区域内的图片,可以拖到任意的地方, 主要原因是imgDragging函数在改变位置,而设置relative的父元素是整个页面。
如果想要不超出moveArea这个区域的话,用下面的函数。
// 在data中加入canOut ,默认false,即不能拖出去。设置为true就和上面代码的效果一样。
imgDragging(e, item) {
if(this.canOut){
item.x = e.clientX - this.imgOffsetX - offLeft
item.y = e.clientY - this.imgOffsetY - offTop
}else{
const area = this.$refs.moveArea
const x=e.clientX;
const y=e.clientY;
const areax1 = area.offsetLeft + offLeft;
const areay1 = area.offsetTop + offTop;
const areax2 = areax1 + area.offsetWidth;
const areay2 = areay1 + area.offsetHeight;
// 只有在区域内的时候才移动
if( x >= areax1 && x <= areax2 && y >= areay1 && y <= areay2){
item.x = e.clientX - this.imgOffsetX - offLeft
item.y = e.clientY - this.imgOffsetY - offTop
}
}
},
应用
这个右边区域的拖动也是利用drag实现的,实际应用中右边区域可以使用vue-draggable-reaizable插件,后续再补个组件。。。