Ant-Design-Vue modal弹窗增加拖拽功能

1,701 阅读2分钟

Ant-Design-Vue modal弹窗增加拖拽功能

​ 负责的一个项目中需要对弹窗进行进行拖拽,所以写了一个拖拽指令完成拖拽功能。

1. 前置知识

需要大致了解Vue2的自定义指令如何书写, 大致就是Vue2提供了一个钩子,让用户去对绑定指令的Dom元素积习进行操作。

自定义指令官网链接 ,或者也可以用文心一言 、chatGPT 查询。

2. 项目中版本号

Vue: ^2.7.10

Ant-Design-Vue: ^1.7.8

3. 具体步骤

1. 大致思路
  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')
    	})
    })
    
  2. 利用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
    	}
    }
    
  3. 设置modal 弹窗Dom的top、left, 并在鼠标up的时候,记住现在的位置,方便下次计算(代码同上一步);

  4. 完善功能:如果指令绑定了值,则下次打开会回到初始位置,其实就是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. 使用步骤
  1. 创建dragModal.js 文件,并粘贴文末的完整代码进去;

  2. 在main.js中引入dragModal.js文件;

    import './plugin/dragModal'
    
  3. 在对应的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)
})