vue自定义v-drag指令实现鼠标拖拽

前言

大家好,我是南木元元,热衷分享有趣实用的文章。本文来分享一下如何在vue中通过自定义指令的方式来实现鼠标拖拽的效果。

实现效果

实现效果就是鼠标按下蓝色区域的图形后,就能够进行元素的拖拽。
在这里插入图片描述

浏览器坐标属性

在介绍自定义指令之前,首先需要知道浏览器中常用的一些坐标属性。

  • Element.clientWidth:元素可视宽度(不包含滚动条)。
  • Element.clientHeight:元素可视高度(不包含滚动条)。
  • MouseEvent.clientX:鼠标相对于浏览器左上顶点的水平坐标(不包含滚动条),与之对应的MouseEvent.pageX:相对于整个文档的水平坐标(即包含滚动)。
  • MouseEvent.clientY:鼠标相对于浏览器左上顶点的垂直坐标(不包含滚动条),与之对应的MouseEvent.pageY:相对于整个文档的垂直坐标(即包含滚动)。
  • HTMLElement.offsetLeft:当前元素左上角相对于父节点(HTMLElement.offsetParent)的左边偏移的距离。
  • HTMLElement.offsetTop:当前元素左上角相对于父节点(HTMLElement.offsetParent)的顶部偏移的距离。
    在这里插入图片描述

实现思路

接下来就可以自定义拖拽指令v-drag了。

首先给需要拖拽的元素设置 position: fixed或者position:absolute定位,使得当前元素的位置是相对于浏览器左上顶点的位置。这里注意区分Position的几个属性值:

  • Absolute:绝对定位,是相对于最近的且不是static定位的父元素来定位。
  • Fixed:绝对定位,是相对于浏览器窗口来定位的,是固定的,不会跟屏幕一起滚动。
  • Relative:相对定位,是相对于其原本的位置来定位的。
  • Relative:相对定位,是相对于其原本的位置来定位的。

元素的位置是通过调整左上顶点坐标来的,所以我们要知道元素拖拽后的左上顶点坐标,这样才能将元素移动到指定位置。

计算出鼠标在移动元素前在元素上的位置 :

let disX = e.clientX - el.offsetLeft;
let disY = e.clientY - el.offsetTop;

知道了鼠标的相对位置,后续的鼠标移动,只要知道移动后的鼠标坐标,就能很容易的把当前位置元素的左上顶点坐标算出来。

计算元素移动后的左上顶点坐标:

el.style.left = e.clientX - disX + "px"; //设置定位元素的左部位置
el.style.top = e.clientY - disY + "px"; //设置定位元素的顶部位置

总体流程:鼠标按下时获取获取鼠标在元素上的位置,每次移动时不断计算和设置元素左上顶点坐标位置,并且在鼠标松开时要禁用掉down的监听事件,否则会一直执行。

实现代码

在组件中使用directives注册一个自定义拖拽指令v-drag,在想要拖动的元素上使用“v-drag”即可。实现代码如下:

<template>
  <div class="box" v-drag></div>
</template>

<script>
export default {
  //注册局部自定义指令
  directives: {
    //el:指令所绑定的元素
    drag(el, bindings) {
      //鼠标按下事件
      el.onmousedown = function(e) {
      	// 获取鼠标在元素上的位置
        let disX = e.clientX - el.offsetLeft;
        let disY = e.clientY - el.offsetTop;
        //鼠标移动事件
        document.onmousemove = function(e) {
          el.style.left = e.clientX - disX + "px"; //设置定位元素的左部位置
          el.style.top = e.clientY - disY + "px"; //设置定位元素的顶部位置
        };
        //鼠标松开事件
        document.onmouseup = function() {
          //要禁用掉down的监听事件,否则会一直执行
          document.onmousemove = document.onmouseup = null;
        };
      };
    },
  },
};
</script>

<style scoped>
.box {
  width: 300px;
  height: 300px;
  background-color: cyan;
  position: fixed;
  left: 100px;
  top: 100px;
}
</style>

结语

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~

好的,对于这个问题,我可以给您一个简单明了的解决方案。 首先,在你的 template 中,你需要创建一个可拖拽元素的 div 元素,如下所示: ``` <template> <div class="drag-element" ref="dragBox" v-on:mousedown="dragStart" v-on:mousemove="drag" v-on:mouseup="dragEnd" > 可拖拽的元素 </div> </template> ``` 在这里,我们创建了一个拥有 `drag-element` 类名的 div 元素,并将其加入了 `ref` 属性从而获得其引用。接下来,我们需要为其绑定 mousedown、mousemove 和 mouseup 事件,从而实现拖拽功能。这里我们分别定义了 `dragStart`、`drag` 和 `dragEnd` 三个方法来分别监听这三个事件。具体的实现如下: ``` <script> import {ref, computed} from 'vue' export default { name: 'DraggableDiv', setup(props) { const dragBox = ref(null); const position = ref({x: 0, y: 0}); const isDragged = ref(false); const dragStart = (event) => { event.preventDefault(); isDragged.value = true; position.value = { x: event.clientX - dragBox.value.getBoundingClientRect().left, y: event.clientY - dragBox.value.getBoundingClientRect().top, }; }; const drag = (event) => { event.preventDefault(); if (isDragged.value) { dragBox.value.style.left = event.clientX - position.value.x + 'px'; dragBox.value.style.top = event.clientY - position.value.y + 'px'; } }; const dragEnd = () => { isDragged.value = false; }; return { dragBox, position, isDragged, dragStart, drag, dragEnd, }; }, }; </script> ``` 在这里,我们使用了 Vue 3 的 Composition API 以及 ref 和 computed 两个函数。我们创建了三个 ref 变量:`dragBox`、`position` 和 `isDragged`。其中,`dragBox` 引用了之前创建的用于拖放的 div 元素,而 `position` 保存了该元素当前的位置信息,`isDragged` 用于记录元素是否正在被拖拽。 我们还定义了三个方法:`dragStart`、`drag` 和 `dragEnd` 分别对应了 mousedown、mousemove 和 mouseup 事件。其中,`dragStart` 方法会在鼠标按下时将 `isDragged` 标记为 true,并计算出当前鼠标位置和元素左上角的位置之间的偏移量。`drag` 方法则根据当前鼠标位置和偏移量计算出元素应该处于的位置,并实现元素的平移。`dragEnd` 方法则在鼠标松开时将 `isDragged` 标记为 false 以结束拖拽。 最后,需要注意的是,为了让拖拽效果更加流畅,你可能还需要在 `drag-element` 类中添加如下 CSS 样式: ``` .drag-element { position: absolute; left: 0px; top: 0px; cursor: move; } ``` 这样,你就可以创建一个简单的可拖拽元素了。希望这能够对你有所帮助!
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南木元元

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值