import Vue from 'vue' // v-drag-modal: 弹窗拖拽 Vue.directive('drag-modal', (el, bindings, vnode) => { Vue.nextTick(() => { let { visible, destroyOnClose } = vnode.componentInstance // 防止未定义 destroyOnClose 关闭弹窗时dom未被销毁,指令被重复调用 if (!visible) return let modal = el.getElementsByClassName('ant-modal')[0] let header = el.getElementsByClassName('ant-modal-header')[0] let left = 0 let top = 0 // 未定义 destroyOnClose 时,dom未被销毁,关闭弹窗再次打开,弹窗会停留在上一次拖动的位置 if (!destroyOnClose) { left = modal.left || 0 top = modal.top || 0 } // top 初始值为 offsetTop top = top || modal.offsetTop // 点击title部分拖动 header.onmousedown = e => { let startX = e.clientX let startY = e.clientY header.left = header.offsetLeft header.top = header.offsetTop el.onmousemove = event => { let endX = event.clientX let endY = event.clientY modal.left = header.left + (endX - startX) + left modal.top = header.top + (endY - startY) + top modal.style.left = modal.left + 'px' modal.style.top = modal.top + 'px' } el.onmouseup = event => { left = modal.left top = modal.top el.onmousemove = null el.onmouseup = null header.releaseCapture && header.releaseCapture() } header.setCapture && header.setCapture() } // 点击表单部分拖动 // modal.onmousedown = e => { // let startX = e.clientX // let startY = e.clientY // header.left = header.offsetLeft // header.top = header.offsetTop // el.onmousemove = event => { // let endX = event.clientX // let endY = event.clientY // modal.left = header.left + (endX - startX) + left // modal.top = header.top + (endY - startY) + top // modal.style.left = modal.left + 'px' // modal.style.top = modal.top + 'px' // } // el.onmouseup = event => { // left = modal.left // top = modal.top // el.onmousemove = null // el.onmouseup = null // header.releaseCapture && header.releaseCapture() // } // header.setCapture && header.setCapture() // } }) })
以上写法会造成页面有元素移动速度无法跟上鼠标移动速度时丢失对元素的操作,并且当页面更新时重新加载组件导致组件位置错误。 更改版如下
import Vue from 'vue' // v-drag-modal: 弹窗拖拽 Vue.directive('drag-modal', { bind: (el, bindings, vnode) => { Vue.nextTick(() => { let { visible, destroyOnClose } = vnode.componentInstance // 防止未定义 destroyOnClose 关闭弹窗时dom未被销毁,指令被重复调用 if (!visible) return let modal = el.getElementsByClassName('ant-modal')[0] let header = el.getElementsByClassName('ant-modal-header')[0] let left = 0 let top = 0 let canMove = false // 未定义 destroyOnClose 时,dom未被销毁,关闭弹窗再次打开,弹窗会停留在上一次拖动的位置 if (!destroyOnClose) { left = modal.left || 0 top = modal.top || 0 } // top 初始值为 offsetTop top = top || modal.offsetTop // 点击title部分拖动 header.onmousedown = e => { canMove = true let startX = e.clientX let startY = e.clientY header.left = header.offsetLeft header.top = header.offsetTop window.onmousemove = event => { if( canMove ){ // console.log("头部鼠标移动", event) let endX = event.clientX let endY = event.clientY modal.left = header.left + (endX - startX) + left modal.top = header.top + (endY - startY) + top modal.style.left = modal.left + 'px' modal.style.top = modal.top + 'px' } } window.onmouseup = event => { canMove = false left = modal.left top = modal.top el.onmousemove = null el.onmouseup = null header.releaseCapture && header.releaseCapture() } header.setCapture && header.setCapture() } // 点击表单部分拖动 modal.onmousedown = e => { canMove = true let startX = e.clientX let startY = e.clientY header.left = header.offsetLeft header.top = header.offsetTop window.onmousemove = event => { if( canMove ){ let endX = event.clientX let endY = event.clientY console.log("内部表单鼠标移动", event, header.left, endX, startX, left, header.left + (endX - startX) + left) modal.left = header.left + (endX - startX) + left modal.top = header.top + (endY - startY) + top modal.style.left = modal.left + 'px' modal.style.top = modal.top + 'px' } } window.onmouseup = event => { canMove = false console.log("鼠标抬起", modal.left) left = modal.left top = modal.top el.onmousemove = null el.onmouseup = null header.releaseCapture && header.releaseCapture() } header.setCapture && header.setCapture() } }) } } )
使用方法:
main.js 引入
import '@/utils/directives.js'
model组件使用处直接使用指令
<a-modal :visible="visibleRecording" ref="modalRef" title="事件上报" v-drag-modal >
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律