目录
需求
dom元素拖拽并限制在父组件范围内
拖拽功能封装
export const initVDrag = (vue) => {
vue.directive('drag', (el) => {
const oDiv = el // 当前元素
oDiv.onmousedown = (e) => {
let target = oDiv
while (
window.getComputedStyle(target).position !== 'absolute' &&
target !== document.body
) {
target = target.parentElement
}
let parent = target.parentNode
document.onselectstart = () => {
return false
}
if (!target.getAttribute('init_x')) {
target.setAttribute('init_x', target.offsetLeft)
target.setAttribute('init_y', target.offsetTop)
}
// e.clientX, e.clientY是鼠标点击的位置
// target.offsetLeft, target.offsetTop是当前元素左上角的位置
// 计算鼠标按下的位置距离当前元素左上角的距离
const disX = e.clientX - target.offsetLeft
const disY = e.clientY - target.offsetTop
// target.clientWidth, target.clientHeight是当前元素的尺寸
// parent.clientWidth, parent.clientHeight是父元素的尺寸
// parent.offsetLeft, parent.offsetTop是父元素左上角的位置
// 可移动范围的位置
const minX = parent.offsetLeft
const maxX = parent.offsetLeft + parent.clientWidth - target.clientWidth
const minY = parent.offsetTop
const maxY = parent.offsetTop + parent.clientHeight - target.clientHeight
document.onmousemove = (e) => {
// 通过事件委托,计算移动的距离,e是最新的鼠标位置,disX、disY是鼠标刚点击时的位置
let l = e.clientX - disX
let t = e.clientY - disY
// 约束移动范围在父元素区域内
if (l < minX) {
l = minX
} else if (l > maxX) {
l = maxX
}
if (t < minY) {
t = minY
} else if (t > maxY) {
t = maxY
}
// 给当前元素样式中的left和top赋值
target.style.left = l + 'px'
target.style.top = t + 'px'
}
document.onmouseup = (e) => {
document.onmousemove = null
document.onmouseup = null
document.onselectstart = null
}
// 不return false的话,可能导致鼠标黏连,鼠标粘在dom上拿不下来,相当于onmouseup失效
return false
}
})
}
使用拖拽功能
以vite为例:
vite-env.d.ts
...
declare module '@utils/directive/vDrag.js'
...
main.ts
...
import { createApp } from 'vue'
import { initVDrag } from '@/utils/directive/vDrag.js'
...
let instance: any = null
instance = createApp(App)
initVDrag(instance)
...
test.vue
<template>
<div v-drag />
</template>