探讨把一个元素从它所在的div 拖动到另一个div内的实现方法

故事背景:
接到一个新需求,要求用vue搞,主要是拖动实现布局,关键点有:单个组件拖动,一行多列里面的组件拖动, 单个组件可以拖入一行多列里, 单个组件的拖动好实现,关键是把一个组件拖动到另一个类似于表格里面,而且有的情况下还需要限制拖动只能在水平方向,自己搜集资料, 实验,终于搞出来了。

原理上主要分为两类:
HTML5自带的拖放api,可用的库有 : Vue.Draggable
使用js 监听鼠标的移动位置, 可用的库有: jquery ui
使用point-event: none(下面会详细说明)
各自缺点
H5拖动的缺点:不能限制在水平 或垂直方向上拖动。

使用原生js缺点:大量的dom操作,代码复杂(jquery ui 封装的比较好了,可直接用)

但是问题来了,这次的需求是把基于jquery ui 的拖动 用 vue 重构,那么用vue.draggable吧, 但是需求里正好有一条是要限制在水平方向上拖动,尴尬,用不了。

寻找方案
最开始的尝试:

<!DOCTYPE html>
<html>
<head>
    <title>vue结合原生js实现拖动</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<div class="ctn ctn1">
    <div class="sub sub1" v-for="(site, index) in list1">
         <div class="dragCtn fixed" :style="{ left: X+'px', top: Y+'px'}"
           @mousedown="mousedown(site, $event)"
           @mousemove.prevent='mousemove(site, $event)'
           @mouseup='mouseup(site, $event)'>
             拖动我
         </div>
   </div>
</div>

<div class="ctn ctn2">
    <div class="sub sub2" v-for="(site, index) in list2"
          @mouseenter='mouseenter(site, $event)'>
         <div class="dragCtn">
             {{ index }} : {{ site.name }}
         </div>
   </div>
</div>
   
</div>

<script>
new Vue({
  el: '#app',
  data: {
    list1: [{name:1, index:0}],
    list2: [{name:'a', index:0}, {name:'b', index:1}, {name:'c', index: 2}, {name:'d', index: 3}],
    vm:'',
    sb_bkx: 0,
    sb_bky: 0,
    is_moving: false,
    X: 0,
    Y: 0
  },
  methods: {
      mousedown: function (site, event) {
        var startx=event.x;
        var starty=event.y;
        this.sb_bkx=startx - event.target.offsetLeft;
        this.sb_bky=starty - event.target.offsetTop;
        this.is_moving = true;
      },
      mousemove: function (site, event) {
          var endx=event.x - this.sb_bkx;
          var endy=event.y - this.sb_bky;
          var _this = this
          if(this.is_moving){
            this.X = endx;
            this.Y = endy;
      }
      },
      mouseup: function (e) {
        this.is_moving = false;
      },
    mouseenter: function (){
      console.log('鼠标进入')
    }
  }
})
</script>

<style>
    .ctn{
        line-height: 50px;
        cursor: pointer;
        font-size: 20px;
        text-align: center;
        float: left;
    }
    .sub:hover{
        background: #e6dcdc;
        color: white;
        width: 100px;
    }
       .ctn1{
           border: 1px solid green;
           width: 100px;
       }
       .ctn2{
           border: 1px solid black;
           width: 100px;
           margin-left: 50px;
       }
       .fixed{
         width: 100px;
      position: fixed;
      background: red;
      left: 0;
      top: 0;
      cursor: move;
       }
</style>
</body>
</html>

就这样实现了基本的拖动,但是在拖动的时候,就不能触 mouseenter 事件了,而且鼠标必须拖动的很慢,移动快一点,拖动的div就跟不上了,这一点到现在还困惑,希望各位大侠指点。

然后在网上找了很多资料,类库,但是不能完全符合我的需求,于是准备自己写了;

   首先是给组件添加mousedown事件,然后mousemove的时候 监听鼠标的位置,再赋值给组件,实现拖动,但是当组件拖动进入另一个元素的时候,无法监听mouseenter, 后来想的办法是给正在拖动的组件加上 point-event:none 属性,就是消除原有的鼠标事件,就可以触发其他组件的mouerenter事件了,point-event 属性的具体用法 可以参考这里:

www.zhangxinxu.com/wordpress/2…

因为拖动是用原生js写的,所以可以限制在水平方向拖动,再加上可以触发mouseenter事件,就正好实现的我的需求。

伪代码如下:

mousedown: function (event, site) {
        document.onmousemove=function (ev) {         
           // 移动的时候给元素增加 point-event:none 属性           
           ...        
    }       
     document.onmouseup=function (ev) {
           // up的时候 要移除point-event属性
           ...        
     }   
 }

但是后来上面要求,要兼容ie10,由于 point-event:none 是H5的属性,于是我赶紧去看看兼容性, 可怕的事发生了,point-event 属性只兼容到 ie11,完蛋!
再想其他办法吧,没了思路,老版本的拖动是基于 jquery ui 的 ,于是去看了 jquery ui 的源码,看看它的拖动是怎么实现的。
jquery ui 拖动实现原理
不熟悉 jquery ui 的拖动方法的可以先看下 这里
看下面这段代码:
$(function() { $( "#draggable" ).draggable(); $( "#droppable" ).droppable({ drop: function( event, ui ) { $( this ).html( "Dropped!" ); } }); });
之前的关键问题就是怎么判断拖动的元素 $( “#draggable” ) 在什么时候 进入了可以放置的区域 $( “#droppable” ) 的,看了源码,它的实现方式 简单来说就是拖动 $( “#draggable” ) 的时候监听 鼠标的位置, 同时获取 $( “#droppable” ) 的区域位置信息,只要鼠标进入该区域,就触发。
顺着这个思路,做了实验 可以满足自己的需求 good !
demo的实现效果如下:
https://user-gold-cdn.xitu.io/2018/11/29/1675d003e2b48622?imageslim
代码地址: https://github.com/YalongYan/vue-drag-layout
拖动布局的实现方式应该还有更好的,欢迎大家提出更好的实现方式。
转载地址:https://www.cnblogs.com/yalong/p/10036463.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您好,要实现将一个input元素拖拽到另一个div中,可以按照以下步骤操作: 1. 给需要拖拽的input元素添加一个mousedown事件监听器,并在事件处理函数中记录鼠标按下时的坐标和元素的初始位置。 ```javascript let dragItem = document.querySelector('input'); let container = document.querySelector('#container'); let startX, startY, dragStartX, dragStartY; dragItem.addEventListener('mousedown', e => { startX = e.clientX; startY = e.clientY; dragStartX = dragItem.offsetLeft; dragStartY = dragItem.offsetTop; }); ``` 2. 给document对象添加一个mousemove事件监听器,并在事件处理函数中计算鼠标移动的距离,并将元素的位置设置为初始位置加上鼠标移动的距离。 ```javascript document.addEventListener('mousemove', e => { e.preventDefault(); if (startX && startY) { let dragX = e.clientX - startX; let dragY = e.clientY - startY; dragItem.style.left = dragStartX + dragX + 'px'; dragItem.style.top = dragStartY + dragY + 'px'; } }); ``` 3. 给document对象添加一个mouseup事件监听器,并在事件处理函数中判断元素是否进入了目标容器中,如果是则将元素添加到目标容器中。 ```javascript document.addEventListener('mouseup', e => { if (startX && startY) { let dropX = e.clientX; let dropY = e.clientY; let containerRect = container.getBoundingClientRect(); if (dropX >= containerRect.left && dropX <= containerRect.right && dropY >= containerRect.top && dropY <= containerRect.bottom) { container.appendChild(dragItem); } dragItem.style.left = dragStartX + 'px'; dragItem.style.top = dragStartY + 'px'; startX = null; startY = null; } }); ``` 以上代码实现了将一个input元素拖拽到另一个div中的功能。当鼠标按下时,记录元素的初始位置和鼠标按下时的坐标;当鼠标移动时,计算鼠标移动的距离,并将元素的位置设置为初始位置加上鼠标移动的距离;当鼠标松开时,判断元素是否进入了目标容器中,如果是则将元素添加到目标容器中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值