vue 中基于drag drop拖放实现左菜单和右画布的功能

参考

vue 中基于html5 drag drap的拖放

功能

在这里插入图片描述

代码

<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插件,后续再补个组件。。。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值