实现elementplus # Dialog的draggable-拖拽功能
```import { DirectiveBinding, ObjectDirective,nextTick } from 'vue'
interface DragDirectiveElement extends HTMLElement {
_dragHandler?: (e: MouseEvent) => void
_dragUpHandler?: () => void
}
export const dialogDrag: ObjectDirective = {
async mounted(targetEl: DragDirectiveElement, binding: DirectiveBinding) {
const el = targetEl.nodeType === 1 ? targetEl : targetEl.$el || targetEl
await nextTick() // 防止页面没有初始化成功
const dialogHeaderEl = el.querySelector('.ep-dialog__header') as HTMLElement
const dragDom = el.querySelector('.ep-dialog') as HTMLElement
console.log('dialogHeaderEl---',dragDom)
if (!dialogHeaderEl || !dragDom) return
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
const onMouseDown = (e: MouseEvent) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
// 获取到的值带px 正则匹配替换
let styL: number, styT: number
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/%/g, '') / 100)
} else {
styL = +sty.left.replace(/px/g, '')
styT = +sty.top.replace(/px/g, '')
}
const onMouseMove = (e: MouseEvent) => {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY
// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`
// 将此时的位置传出去
if (binding.value) {
binding.value({ x: e.pageX, y: e.pageY })
}
}
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
}
dialogHeaderEl.addEventListener('mousedown', onMouseDown)
el._dragHandler = onMouseDown
},
unmounted(el: DragDirectiveElement) {
const dialogHeaderEl = el.querySelector('.el-dialog__header') as HTMLElement
if (dialogHeaderEl && el._dragHandler) {
dialogHeaderEl.removeEventListener('mousedown', el._dragHandler)
}
}
}
main.ts
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { directives } from './directives'
const app = createApp(App)
// 批量注册指令
Object.entries(directives).forEach(([name, directive]) => {
app.directive(name, directive)
})
app.mount('#app')
在组件中直接使用
<template>
<!-- 使用 v-drag 指令 -->
<el-dialog v-drag />
</template>