vue通过自定义指令实现拖拽功能

vue拖拽自定义指令

在实现拖拽功能之前,首先需要理解鼠标事件的这几个属性clientY、pageY、screenY、layerY、offsetY怎么用,以及彼此之间有什么区别

  1. clientY 指的是鼠标相对于浏览器视口左上角的偏移(即距离可视页面左上角的距离,clientY在页面无滚动条的情况下值等同于pageY)
  2. pageY 指的是鼠标相对于页面左上角的偏移 (其值不会受滚动条的响)IE9之下并不支持这个属性
// pageY:鼠标相对于浏览器视口的偏移加上文档的滚动条隐藏的高度减去文档的clientTop.
const pageY = event.clientY +document.documentElement. scrollTop-document.documentElement.clientTop

为何要减去document.documentElement.clientTop,这是IE8之下浏览器特有的文档的偏移,即使设置html,body的padding和margin为0也不会影响其值。

  1. screenY 指的是鼠标相对于显示器屏幕左上角的偏移
  2. layerY 指的是找到它或它父级元素中最近具有定位的左上角距离
如果元素的position样式不是默认的static,我们说这个元素具有定位属性。
在当前触发鼠标事件的元素和它的祖先元素中找到最近的具有定位属性的元素,计算鼠标与其的偏移值,以找到元素的border的左上角的外交点作为相对点。如果找不到具有定位属性的元素,那么就相对于当前页面计算偏移,此时等同于pageY)
简单点说:layerY返回的是相对position:relative,position:absolute的left和top
  1. offsetY 指的是相对于它自己左上角的距离( IE专有的属性)
offsetY和layerY的不同在于,前者在计算偏移值时,相对于元素的border左上角的内交点,因此当鼠标位于元素的border上时,偏移值是一个负值。 另外offsetY并不在乎触发事件的元素是否有定位属性,它总是相对于触发事件的元素来计算偏移值
offsetX offsetY返回的是相对于当前元素的左上角的left和top

可以通过下面这张图了解下:
在这里插入图片描述
我们通过下面这张表看下他们之间的区别

相同点不同点
clientY距离页面左上角距离受页面滚动的影响
pageY距离页面左上角距离不受页面滚动影响
相同点不同点
layerY距离元素的左上角距离受元素的定位的影响,会从本元素往上找到第一个定位的元素的左上角
offsetY距离元素左上角的距离计算相对于本元素的左上角,不在乎定位问题,计算的是内交点。是IE浏览器的特有属性

拖拽原理及思路

主体思路:

拖拽主要用到了鼠标的几个事件

  • onmousedown:鼠标按下事件
  • onmousemove:鼠标移动事件
  • onmouseup:鼠标抬起事件
基本原理:

根据鼠标的移动来移动被拖拽的元素,鼠标的移动即x、y坐标的变化;元素的移动即style.position的top和left的改变。当然,并不是任何时候移动鼠标都要造成元素的移动,而应该判断鼠标左键的状态是否为按下状态,是否是在可拖拽的元素上按下。

拖拽状态 = 鼠标在元素上按下的时候{      
     记录鼠标x、y坐标      
     记录元素x、y坐标      
}   
鼠标在元素上移动的时候{      
     元素y = 现在鼠标y - 原来鼠标y + 原来元素y      
     元素x = 现在鼠标x - 原来鼠标x + 原来元素x      
}      
鼠标在任何时候放开的时候{      
     鼠标弹起来的时候不再移动      
} 

拖拽功能代码实现

// 在vue脚手架项目main.js中:

// 全局自定义拖拽组件
Vue.directive('drag', {
  //1.指令绑定到元素上回立刻执行bind函数,只执行一次
  //2.每个函数中第一个参数永远是el,表示绑定指令的元素,el参数是原生js对象
  bind: function (el, elementObj) {
    let dragBox = el; //获取当前元素
    dragBox.style.position = 'absolute'; // 拖拽元素使用定位,脱离文档流
    dragBox.onmousedown = e => {
      //鼠标相对元素的位置
      let disX = e.clientX - dragBox.offsetLeft;
      let disY = e.clientY - dragBox.offsetTop;
      document.onmousemove = e => {
        //鼠标的位置减去鼠标相对元素的位置,得到元素的位置
        let left = e.clientX - disX;
        let top = e.clientY - disY;
        //移动当前元素
        dragBox.style.left = left + 'px';
        dragBox.style.top = top + 'px';
      };
      document.onmouseup = e => {
        //鼠标弹起来的时候不再移动
        document.onmousemove = null;
        //预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)
        document.onmouseup = null;
        // 对外暴露元素相对于父级位置
        elementObj.value.left = dragBox.style.left;
        elementObj.value.top = dragBox.style.top;
      };
    };
  }
});

// 使用
<div class="dragBox">
	<div v-drag="elementPos" class="dragMe"></div>
</div>
<script>
  export default {
    name: 'dragRotateZoom',
    data(){
      return{
        // 元素相对于父级位置
        elementPos: {
          left: null,
          top: null,
        },
      }
    },
    watch:{
      elementPos:{
        handler(val){
          console.log(val, 789);// 实时获取拖拽元素相对于父级位置
        },
        deep: true, immediate: true
      }
    }
</script>

// css
.dragBox{
      width:300px;
      height:300px;
      background: #ccc;
      position: relative;
      .dragMe{
        cursor: move;
        width: 100px;
        height: 100px;
        background: burlywood;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    }

最终效果

在这里插入图片描述
大概就是这么多,使用的话直接通过v-drag即可实现拖拽功能,方便高效。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现小方块的拖拽效果,可以通过自定义指令实现。以下是实现步骤: 1. 在指令中绑定拖拽元素的事件监听器,包括mousedown、mousemove和mouseup事件。 2. 在mousedown事件中记录鼠标按下时的位置和拖拽元素的初始位置。 3. 在mousemove事件中计算鼠标移动的距离,并将拖拽元素的位置进行相应的调整。 4. 在mouseup事件中清除事件监听器。 下面是一个实现小方块拖拽效果的自定义指令的示例代码: ```javascript // 注册自定义指令 Vue.directive('drag', { bind: function (el, binding, vnode) { // 记录拖拽元素的初始位置 var initX, initY, startX, startY; // 鼠标按下时的事件处理函数 function mouseDownHandler(e) { initX = el.offsetLeft; initY = el.offsetTop; startX = e.clientX; startY = e.clientY; // 添加事件监听器 document.addEventListener('mousemove', mouseMoveHandler); document.addEventListener('mouseup', mouseUpHandler); } // 鼠标移动时的事件处理函数 function mouseMoveHandler(e) { var deltaX = e.clientX - startX; var deltaY = e.clientY - startY; // 计算拖拽元素的新位置 var newX = initX + deltaX; var newY = initY + deltaY; // 设置拖拽元素的新位置 el.style.left = newX + 'px'; el.style.top = newY + 'px'; } // 鼠标松开时的事件处理函数 function mouseUpHandler() { // 移除事件监听器 document.removeEventListener('mousemove', mouseMoveHandler); document.removeEventListener('mouseup', mouseUpHandler); } // 添加鼠标按下事件监听器 el.addEventListener('mousedown', mouseDownHandler); } }); ``` 使用该指令时,只需要在需要实现拖拽效果的小方块元素上添加v-drag指令即可: ```html <div v-drag class="drag-box"></div> ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值