Ant-Design-Vue modal弹窗增加拖拽功能
负责的一个项目中需要对弹窗进行进行拖拽,所以写了一个拖拽指令完成拖拽功能。
1. 前置知识
需要大致了解Vue2的自定义指令如何书写, 大致就是Vue2提供了一个钩子,让用户去对绑定指令的Dom元素积习进行操作。
自定义指令官网链接 ,或者也可以用文心一言 、chatGPT 查询。
2. 项目中版本号
Vue: ^2.7.10
Ant-Design-Vue: ^1.7.8
3. 具体步骤
1. 大致思路
-
对modal组件进行指令的绑定,通过指令的参数获取到modal组件的Dom结构进行操作;
modal绑定指令 v-drag-modal, 如果传值代表下次打开会在设置的初始位置,不传值表示记住拖拽的位置 <a-modal v-model="visible" centered width="760px" v-drag-modal="true"> ... </a-modal> ============== 分隔线 ============== dragModal.js部分 import Vue from 'vue' // 注册自定义拖拽指令,弥补 modal 组件不能拖拽 Vue.directive('drag-modal', (el, bindings, vnode) => { Vue.nextTick(() => { const modal = el.querySelector('.ant-modal') const header = el.querySelector('.ant-modal-header') }) }) -
利用mousedown mousemove mouseup,获取鼠标的位置,计算出移动的差值;
dragModal.js部分 // 这里唯一要注意的就是 mousemove 和 mouseup 要绑定在el上,这样才能鼠标快速移动的时候,也是在拖拽范围内的 header.onmousedown = e => { const startX = e.clientX const startY = e.clientY el.onmousemove = event => { const endX = event.clientX const endY = event.clientY modal.left = (endX - startX) + left modal.top = (endY - startY) + top modal.style.top = modal.top + 'px' modal.style.left = modal.left + 'px' } el.onmouseup = event => { left = modal.left || 0 top = modal.top || 0 el.onmousemove = null el.onmouseup = null } } -
设置modal 弹窗Dom的top、left, 并在鼠标up的时候,记住现在的位置,方便下次计算(代码同上一步);
-
完善功能:如果指令绑定了值,则下次打开会回到初始位置,其实就是top、left置零。
const resetPosition = !!bindings.value // 传值重置 if (resetPosition) { modal.style.top = 0 + 'px' modal.style.left = 0 + 'px' } // 不传值 获取上一次的位置值 if (!resetPosition) { left = modal.left || 0 top = modal.top || 0 }
2. 使用步骤
-
创建dragModal.js 文件,并粘贴文末的完整代码进去;
-
在main.js中引入dragModal.js文件;
import './plugin/dragModal' -
在对应的modal组件中使用指令。
<a-modal ... v-drag-modal="true" >
3. 完整代码
优化版本
import Vue from 'vue'
// 注册自定义拖拽指令,弥补 modal 组件不能拖动的缺陷
Vue.directive('drag-modal', (el, bindings, vnode) => {
setTimeout(() => {
const { visible, destroyOnClose } = vnode.componentInstance
const modal = el.querySelector('.ant-modal')
const header = el.querySelector('.ant-modal-header')
const resetPosition = !!bindings.value
// 防止未定义 destroyOnClose 关闭弹窗时dom未被销毁,指令被重复调用
if (!visible) {
if (modal) {
modal.modalPosition = {
top: 0,
left: 0
}
setTimeout(() => {
modal.style.top = 0 + 'px'
modal.style.left = 0 + 'px'
}, 1000)
}
return
}
// 鼠标变成可移动的指示
header.style.cursor = 'move'
// top 初始值为 offsetTop
header.onmousedown = e => {
const startX = e.clientX
const startY = e.clientY
document.onmousemove = event => {
const endX = event.clientX
const endY = event.clientY
modal.left = (endX - startX) + (modal.modalPosition ? modal.modalPosition.left : 0)
modal.top = (endY - startY) + (modal.modalPosition ? modal.modalPosition.top : 0)
console.log(modal.top, modal.left)
modal.style.top = modal.top + 'px'
modal.style.left = modal.left + 'px'
}
document.onmouseup = event => {
modal.modalPosition = {
top: modal.top,
left: modal.left
}
document.onmousemove = null
document.onmouseup = null
}
}
}, 100)
})