vue dialog 可拖拽放大缩小

858 阅读2分钟

通过mousemove判断dialog哪条边缩放,配合mousedown开启移动、尺寸修改。

dialog.ts

// element-plus 的 dialog 的拖拽方法
const dialogDrag = (el: any, binding: any) => {
    addEventFun();

    function addEventFun() {
        // 可视窗口的宽度
        const clientWidth = document.documentElement.clientWidth
        // 可视窗口的高度
        const clientHeight = document.documentElement.clientHeight

        // 弹窗的容器
        const domDrag = el.parentElement.parentElement

        // 拖拽的div
        if (domDrag) {
            // 获取元素
            const dialogDom = domDrag;
            const headerDom = dialogDom.getElementsByClassName('el-dialog__header')[0];
            const dialogBoxDom = dialogDom.parentElement;

            // 初始化变量
            let startX, startY, initialX, initialY, newWidth, newHeight;
            let isDrag = false;
            let dragPosition = {
                x: 0,
                y: 0,
            };
            let isResizing : any = false;
            let isMousedown = false;

            headerDom.style.cursor = 'move';
            dialogDom.style.position = 'absolute';
            dialogDom.style.width = '60%';
            dialogDom.style.height = '80%';
            dialogDom.style.top = '10%';
            dialogDom.style.left = '20%';
            dialogDom.style.margin = '0';
            
            // 鼠标移动改变指针样式
            dialogDom.addEventListener('mousemove', (e: any) => {
                if (isMousedown) return;
                const size = 5;
                const width = dialogDom.clientWidth;
                const height = dialogDom.clientHeight;
                const dialogBoxX = e.pageX - dialogBoxDom.offsetLeft;
                const dialogBoxY = e.pageY - dialogBoxDom.offsetTop;
                startX = dialogBoxX - dialogDom.offsetLeft;
                startY = dialogBoxY - dialogDom.offsetTop;
                // console.log(width, height);
                 if (startX < size && startY < size) {
                    dialogDom.style.cursor = 'nw-resize';
                    isResizing = 'top-left';
                } else  if (startX > width - size && startY > height - size) {
                    dialogDom.style.cursor = 'nw-resize';
                    isResizing = 'bottom-right';
                }  else if (startX > width - size && startY < size) {
                    dialogDom.style.cursor = 'ne-resize';
                    isResizing = 'top-right';
                } else if (startX < size && startY > height - size) {
                    dialogDom.style.cursor = 'ne-resize';
                    isResizing = 'bottom-left';
                } else if (startX < size) {
                    dialogDom.style.cursor = 'e-resize';
                    isResizing = 'left';
                }  else if (startX > width - size) {
                    dialogDom.style.cursor = 'e-resize';
                    isResizing = 'right';
                }  else if (startY < size) {
                    dialogDom.style.cursor = 'n-resize';
                    isResizing = 'top';
                }  else if (startY > height - size) {
                    dialogDom.style.cursor = 'n-resize';
                    isResizing = 'bottom';
                } else {
                    dialogDom.style.cursor = 'default';
                    isResizing = false;
                }
            });
            // 拖拽
            headerDom.addEventListener('mousedown', (e: any) => {
                isDrag = true;
                dragPosition.x = e.pageX - dialogBoxDom.offsetLeft - dialogDom.offsetLeft;
                dragPosition.y = e.pageY - dialogBoxDom.offsetTop - dialogDom.offsetTop;
            });
            // 鼠标按下判断是否开启尺寸拖拽
            dialogDom.addEventListener('mousedown', (e: any) => {
                if (!isResizing) return;
                isMousedown = true;
            });
            // 按住鼠标移动改变尺寸
            dialogDom.parentElement.addEventListener('mousemove', (e: any) => {
                const domWidth = dialogDom.clientWidth;
                const domHeight = dialogDom.clientHeight;
                const domTop = dialogDom.offsetTop;
                const domLeft = dialogDom.offsetLeft;
                const dialogBoxX = e.pageX - dialogBoxDom.offsetLeft;
                const dialogBoxY = e.pageY - dialogBoxDom.offsetTop;
                const minWidth = 100;
                const minHeight = 100;
                // 拖拽
                if(isDrag) {
                    // console.log(dialogDom.clientWidth)
                    dialogDom.style.left = dialogBoxX - dragPosition.x + 'px';
                    dialogDom.style.top = dialogBoxY - dragPosition.y + 'px';
                }
                if (!isMousedown) return;
                switch (isResizing) {
                    case 'top-left':
                        moveTop();
                        moveLeft();
                        break;
                    case 'bottom-right':
                        moveBottom();
                        moveRight();
                        break;
                    case 'top-right':
                        moveTop();
                        moveRight();
                        break;
                    case 'bottom-left':
                        moveBottom();
                        moveLeft();
                        break;
                    case 'left':
                        moveLeft();
                        break;
                    case 'right':
                        moveRight();
                        break;
                    case 'top':
                        moveTop();
                        break;
                    case 'bottom':
                        moveBottom();
                        break;
                    default:
                        break;
                }
                function moveLeft() {
                    const width = domWidth + domLeft - dialogBoxX;
                    if (domWidth < minWidth && width < domWidth) return;
                    dialogDom.style.left = dialogBoxX + 'px';
                    dialogDom.style.width = width + 'px';
                }
                function moveRight() {
                    const width = dialogBoxX - domLeft;
                    if (domWidth < minWidth && width < domWidth) return;
                    dialogDom.style.width = width + 'px';
                }
                function moveTop() {
                    const height = domHeight + domTop - dialogBoxY;
                    if (domHeight < minHeight && height < domHeight) return;
                    dialogDom.style.top = dialogBoxY + 'px';
                    dialogDom.style.height = height + 'px';
                }
                function moveBottom() {
                    const height = dialogBoxY - domTop;
                    if (domHeight < minHeight && height < domHeight) return;
                    dialogDom.style.height = height + 'px';
                }
            });
            // 鼠标抬起
            dialogDom.parentElement.addEventListener('mouseup', (e: any) => {
                isDrag = false;
                isMousedown = false;
            });
        } else {
            setTimeout(() => {
                addEventFun();
            }, 1000);
        }
    }

}

export default dialogDrag

main.ts

import { createApp } from 'vue'
import AppVue from './AppVue.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import dialogDrag from "./util/dialog"

createApp(AppVue)
    .use(ElementPlus)
    .directive('dialogdrag', {
        mounted(el, binding) {
            dialogDrag(el, binding)
        }
    })
  .mount('#app')
  .$nextTick(() => {
    postMessage({ payload: 'removeLoading' }, '*')
  })

demo.vue

<template>
    <el-dialog v-model="show" title="" width="50%" :append-to-body= :close-on-click-modal="false" :show-close="false">
        <div v-dialogdrag>内容</div>
    </el-dialog>
</template>