自定义拖拽指令
悬浮可拖拽组件的实现涉及到鼠标事件的应用,为了提高代码可复用性,本文将拖拽功能的实现封装为Vue指令,可通过全局引用直接调用。
在src/utils/
目录下新建drag.ts
:
const drag = {
beforeMount(el: any) {
el.style.cursor = "move";
el.onmousedown = (e: any) => {
const mouseX = e.clientX;
const mouseY = e.clientY;
const domX = el.offsetLeft;
const domY = el.offsetTop;
const maxX = document.body.clientWidth - el.offsetWidth;
const maxY = document.documentElement.clientHeight - el.offsetHeight;
document.onmousemove = function (e) {
const deltaX = e.clientX - mouseX;
const deltaY = e.clientY - mouseY;
let newX = domX + deltaX;
let newY = domY + deltaY;
//边界控制
if (newX < 0) newX = 0;
else if (newX > maxX) newX = maxX;
if (newY < 0) newY = 0;
else if (newY > maxY) newY = maxY;
el.style.left = newX + "px";
el.style.top = newY + "px";
};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
};
return false;
};
},
};
const directives = {
install: function (app: any) {
app.directive("drag", drag);
},
};
export default directives;
在src/main.ts
中引入该指令:
import drag from "@/utils/drag";
app.use(drag)
给要拖拽的节点添加v-drag
属性,同时在style
中设置position: fixed
:
<template>
<div class="dragDiv" v-drag="true"> ... </div>
</template>
<style>
.dragDiv {
position: fixed;
width: 50px;
height: 50px;
right: 10px;
bottom: 10px;
z-index: 10;
}
</style>
阻止点击事件
拖拽动作涉及mousedown
、mousemove
、mouseup
事件,而mousedown
和mouseup
又会触发click事件。触发顺序:mousedown
→mousemove
→mouseup
→click
。
如果给click
事件绑定了函数,如点击打开对话框,那么在拖拽该组件后也会触发对应的click
操作,这往往是我们不希望的,所以需要区分开拖拽和click
,阻止click
的执行。
实现思路:在mousemove
事件触发时,给组件添加“拖拽”标记,当click
事件触发时,先检查该标记以决定是否继续执行。
在拖拽指令的基础上进行修改:
el.onmousedown = (e: any) => {
//拖拽标记还原
el.dragFlag = false;
...
document.onmousemove = function (e) {
//设置拖拽标记
el.dragFlag = true;
...
}
...
}
在组件的click
处理函数中添加dragFlag
标记判断:
<template>
<div ref="dragRef" class="dragDiv" v-drag="true" @click="handleClick">...</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
const dragRef = ref(null);
function handleClick() {
//如果是拖拽,则不运行后续代码
if (dragRef.value.dragFlag) return;
...
}
</script>