Vue3 + Ant Design Vue Modal 对话框可拖拽指令

1、html部分 

<div v-dialogDrag id="modalBox">

      <a-modal

        v-model:visible="visible"

        title="我要拖拽"

        :getContainer="getContainer"

        :force-render="true" // 强制渲染 不管有没有开启modal 页面都进行DOM加载

      >

        <p>Some contents...</p>

      </a-modal>

    </div>

2、ts部分

说明:modal默认挂载到body下,getContainer  函数是为了让modal挂载到父盒子modalBox下,不然指令中 el 获取不到modal的DOM节点

const visible = ref<boolean>(false);

const getContainer = () => {

  return document.getElementById("modalBox");

};

3、指令代码部分

本人文件层级

3.1 index.ts文件

import dialogDrag from "./modules/dialogDrag"

// 统一入口

export default function directive(app: any) {

    app.directive('dialogDrag', dialogDrag)

}

3.2 dialogDrag.ts (核心代码)

说明:必须使用 nextTick 不然获取DOM元素会为空

import { nextTick } from "vue";

export default {

    mounted(el: any, binding?: any) {

        nextTick(() => {

            // 获取对应DOM

            const dialogHeaderEl = el.querySelector('.xz-modal-header')

            const dragDom = el.querySelector('.xz-modal')

            dialogHeaderEl.style.cssText += ';cursor:move;'

            // dragDom.style.cssText += ';bottom:0px;'

            // 获取原有属性 火狐谷歌 window.getComputedStyle(dom元素, null);

            const sty = (function () {

                return (dom: any, attr: any) => getComputedStyle(dom, null)[attr]

            })()

            dialogHeaderEl.onmousedown = (e: any) => {

                // 鼠标按下,计算当前元素距离可视区的距离

                const disX = e.clientX - dialogHeaderEl.offsetLeft

                const disY = e.clientY - dialogHeaderEl.offsetTop

                const screenWidth = document.body.clientWidth // body当前宽度

                const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度,可某些环境下无法获取)

                const dragDomWidth = dragDom.offsetWidth // 对话框宽度

                const dragDomheight = dragDom.offsetHeight // 对话框高度

                const minDragDomLeft = dragDom.offsetLeft

                const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth

                const minDragDomTop = dragDom.offsetTop

                const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight

                // 获取到的值带px 正则匹配替换

                let styL: any = sty(dragDom, 'left')

                // 为兼容ie

                if (styL === 'auto') styL = '0px'

                let styT: any = sty(dragDom, 'top')

                // console.log(styL)

                // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px

                if (styL.includes('%')) {

                    styL = +document.body.clientWidth * (+styL.replace(/%/g, '') / 100)

                    styT = +document.body.clientHeight * (+styT.replace(/%/g, '') / 100)

                } else {

                    styL = +styL.replace(/px/g, '')

                    styT = +styT.replace(/px/g, '')

                }

                document.onmousemove = function (e) {

                    // 通过事件委托,计算移动的距离

                    let left = e.clientX - disX

                    let top = e.clientY - disY

                    // 边界处理

                    if (-(left) > minDragDomLeft) {

                        left = -(minDragDomLeft)

                    } else if (left > maxDragDomLeft) {

                        left = maxDragDomLeft

                    }

                    if (-(top) > minDragDomTop) {

                        top = -(minDragDomTop)

                    } else if (top > maxDragDomTop) {

                        top = maxDragDomTop

                    }

                    // 移动当前元素

                    dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`

                }

                document.onmouseup = function (e: any) {

                    document.onmousemove = null

                    document.onmouseup = null

                }

                return false

            }

        })

    }

}

main.ts中引入 全局使用

const app = createApp(App);

import App from "./App.vue";

import directive from './common/Directive/index'; // 统一自定义指令入口

directive(app)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容