el-dialog弹窗拖拽+水平方向伸缩

文章介绍了一个在Vue项目中创建自定义指令`v-dialogDrag`的方法,该指令用于实现ElementUI的弹窗组件的拖拽、全屏和拉伸功能。通过绑定这个指令到弹窗元素,用户可以进行拖动、双击全屏以及通过控制块进行尺寸调整。代码详细处理了鼠标按下、移动和释放事件,以及不同方向的拉伸操作,确保了弹窗在不同状态下的正确显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import Vue from 'vue'

/*
 *  定义一个directives.js,在入口文件main.js中import './utils/directives.js';
 *  给elementUI的dialog上加上 v-dialogDrag 指令就可以实现弹窗的全屏和拉伸了。
 */
// v-dialogDrag: 弹窗拖拽+水平方向伸缩
Vue.directive('dialogDrag', {
    bind(el, binding, vnode, oldVnode) {
        //弹框可拉伸最小宽高
        let minWidth = 400;
        let minHeight = 300;
        //初始非全屏
        let isFullScreen = false;
        //当前宽高
        let nowWidth = 0;
        let nowHight = 0;
        //当前顶部高度
        let nowMarginTop = 0;
        //获取弹框头部(这部分可双击全屏)
        const dialogHeaderEl = el.querySelector('.el-dialog__header');
        //弹窗
        const dragDom = el.querySelector('.el-dialog');
        //给弹窗加上overflow auto;不然缩小时框内的标签可能超出dialog;
        dragDom.style.overflow = "auto";
        //清除选择头部文字效果
        dialogHeaderEl.onselectstart = new Function("return false");
        //头部加上可拖动cursor
        dialogHeaderEl.style.cursor = 'move';
        // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
        const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
        let moveDown = (e) => {
            // 鼠标按下,计算当前元素距离可视区的距离
            const disX = e.clientX - dialogHeaderEl.offsetLeft;
            const disY = e.clientY - dialogHeaderEl.offsetTop;
            // 获取到的值带px 正则匹配替换
            let styL, styT;
            // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
            if (sty.left.includes('%')) {
                styL = +document.body.clientWidth * (+sty.left.replace(/%/g, '') / 100);
                styT = +document.body.clientHeight * (+sty.top.replace(/%/g, '') / 100);
            } else {
                styL = +sty.left.replace(/px/g, '');
                styT = +sty.top.replace(/px/g, '');
            };
            document.onmousemove = function(e) {
                // 通过事件委托,计算移动的距离
                const l = e.clientX - disX;
                const t = e.clientY - disY;
                // 移动当前元素
                dragDom.style.left = `${l + styL}px`;
                dragDom.style.top = `${t + styT}px`;
                //将此时的位置传出去
                //binding.value({x:e.pageX,y:e.pageY})
            };
            document.onmouseup = function(e) {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        }
        dialogHeaderEl.onmousedown = moveDown;
        //双击头部效果
        dialogHeaderEl.ondblclick = (e) => {
            if (isFullScreen == false) {
                nowHight = dragDom.clientHeight;
                nowWidth = dragDom.clientWidth;
                nowMarginTop = dragDom.style.marginTop;
                dragDom.style.left = 0;
                dragDom.style.top = 0;
                dragDom.style.height = "100VH";
                dragDom.style.width = "100VW";
                dragDom.style.marginTop = 0;
                isFullScreen = true;
                dialogHeaderEl.style.cursor = 'initial';
                dialogHeaderEl.onmousedown = null;
            } else {
                dragDom.style.height = "auto";
                dragDom.style.width = nowWidth + 'px';
                dragDom.style.marginTop = nowMarginTop;
                isFullScreen = false;
                dialogHeaderEl.style.cursor = 'move';
                dialogHeaderEl.onmousedown = moveDown;
            }
        }

        //拉伸(右下方)
        let resizeEl = document.createElement("div");
        dragDom.appendChild(resizeEl);
        //在弹窗右下角加上一个10-10px的控制块
        resizeEl.style.cursor = 'se-resize';
        resizeEl.style.position = 'absolute';
        resizeEl.style.height = '10px';
        resizeEl.style.width = '10px';
        resizeEl.style.right = '0px';
        resizeEl.style.bottom = '0px';
        resizeEl.style.zIndex = '99';
        //鼠标拉伸弹窗
        resizeEl.onmousedown = (e) => {
            // 记录初始x位置
            let clientX = e.clientX;
            // 鼠标按下,计算当前元素距离可视区的距离
            let disX = e.clientX - resizeEl.offsetLeft;
            let disY = e.clientY - resizeEl.offsetTop;
            document.onmousemove = function(e) {
                e.preventDefault(); // 移动时禁用默认事件

                // 通过事件委托,计算移动的距离
                let x = e.clientX - disX + (e.clientX - clientX); //这里 由于elementUI的dialog控制居中的,所以水平拉伸效果是双倍
                let y = e.clientY - disY;
                //比较是否小于最小宽高
                dragDom.style.width = x > minWidth ? `${x}px` : minWidth + 'px';
                dragDom.style.height = y > minHeight ? `${y}px` : minHeight + 'px';
            };
            //拉伸结束
            document.onmouseup = function(e) {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        }

        //拉伸(右边)
        let resizeElR = document.createElement("div");
        dragDom.appendChild(resizeElR);
        //在弹窗右下角加上一个10-10px的控制块
        resizeElR.style.cursor = 'w-resize';
        resizeElR.style.position = 'absolute';
        resizeElR.style.height = '100%';
        resizeElR.style.width = '10px';
        resizeElR.style.right = '0px';
        resizeElR.style.top = '0px';
        //鼠标拉伸弹窗
        resizeElR.onmousedown = (e) => {
            let elW = dragDom.clientWidth;
            let EloffsetLeft = dragDom.offsetLeft;
            // 记录初始x位置
            let clientX = e.clientX;
            document.onmousemove = function(e) {
                e.preventDefault(); // 移动时禁用默认事件
                //右侧鼠标拖拽位置
                if (clientX > EloffsetLeft + elW - 10 && clientX < EloffsetLeft + elW) {
                    //往左拖拽
                    if (clientX > e.clientX) {
                        if (dragDom.clientWidth < minWidth) {} else {
                            dragDom.style.width = elW - (clientX - e.clientX) * 2 + 'px';
                        }
                    }
                    //往右拖拽
                    if (clientX < e.clientX) {
                        dragDom.style.width = elW + (e.clientX - clientX) * 2 + 'px';
                    }
                }

            };
            //拉伸结束
            document.onmouseup = function(e) {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        }

        //拉伸(左边)
        let resizeElL = document.createElement("div");
        dragDom.appendChild(resizeElL);
        //在弹窗右下角加上一个10-10px的控制块
        resizeElL.style.cursor = 'w-resize';
        resizeElL.style.position = 'absolute';
        resizeElL.style.height = '100%';
        resizeElL.style.width = '10px';
        resizeElL.style.left = '0px';
        resizeElL.style.top = '0px';
        //鼠标拉伸弹窗
        resizeElL.onmousedown = (e) => {
            let elW = dragDom.clientWidth;
            let EloffsetLeft = dragDom.offsetLeft;
            // 记录初始x位置
            let clientX = e.clientX;
            document.onmousemove = function(e) {
                e.preventDefault(); // 移动时禁用默认事件
                //左侧鼠标拖拽位置
                if (clientX > EloffsetLeft && clientX < EloffsetLeft + 10) {
                    //往左拖拽
                    if (clientX > e.clientX) {
                        dragDom.style.width = elW + (clientX - e.clientX) * 2 + 'px';
                    }
                    //往右拖拽
                    if (clientX < e.clientX) {
                        if (dragDom.clientWidth < minWidth) {} else {
                            dragDom.style.width = elW - (e.clientX - clientX) * 2 + 'px';

                        }
                    }
                }

            };
            //拉伸结束
            document.onmouseup = function(e) {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        }

        // 拉伸(下边)
        let resizeElB = document.createElement("div");
        dragDom.appendChild(resizeElB);
        //在弹窗右下角加上一个10-10px的控制块
        resizeElB.style.cursor = 'n-resize';
        resizeElB.style.position = 'absolute';
        resizeElB.style.height = '10px';
        resizeElB.style.width = '100%';
        resizeElB.style.left = '0px';
        resizeElB.style.bottom = '0px';
        //鼠标拉伸弹窗
        resizeElB.onmousedown = (e) => {
            let EloffsetTop = dragDom.offsetTop;
            let ELscrollTop = el.scrollTop;
            let clientY = e.clientY;
            let elH = dragDom.clientHeight;
            document.onmousemove = function(e) {
                e.preventDefault(); // 移动时禁用默认事件
                //底部鼠标拖拽位置
                if (ELscrollTop + clientY > EloffsetTop + elH - 20 && ELscrollTop + clientY < EloffsetTop + elH) {
                    //往上拖拽
                    if (clientY > e.clientY) {
                        if (dragDom.clientHeight < minHeight) {} else {
                            dragDom.style.height = elH - (clientY - e.clientY) * 2 + 'px';
                        }
                    }
                    //往下拖拽
                    if (clientY < e.clientY) {
                        dragDom.style.height = elH + (e.clientY - clientY) * 2 + 'px';
                    }
                }
            };
            //拉伸结束
            document.onmouseup = function(e) {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        }
    }
})
需要加上:close-on-click-modal="false",否则拖拽dialog弹窗四个斜角时,会出现弹窗消失的问题
<el-dialog v-dialogDrag :visible.sync="dialogVisible" width="60%" :close-on-click-modal="false" :before-close="handleClose">
      <uploadDialog v-if="dialogVisible" @close='handleClose' ref="uploadDialog"></uploadDialog>
</el-dialog>

<think>首先,用户的问题是关于在 Vue 中使用 ElementUI 的 el-dialog 组件实现弹框的八角伸缩拖拽功能。用户要求提供一个实现案例。 我需要参考系统级指令: - 所有行内数学表达式必须使用 $...$ 格式,但在这个问题中没有数学内容,所以可能不需要。 - 独立公式使用 $$...$$ 格式,但这里没有公式。 - LaTeX 语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识,如 [^1]。 用户可见层的要求: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 用户提供的引用: - 引用[1]:关于为 el-Dialog 添加拖拽功能的实现。 - 引用[2]:实现拖拽功能的方法,通过给标题添加 mousedown 事件。 - 引用[3]:el-dialog 的基本实现代码。 用户的问题:实现八角伸缩拖拽功能。八角伸缩可能指的是调整弹框大小(resize),拖拽是移动位置(drag)。 关键点: - 拖拽功能:可以通过监听标题的 mousedown 事件来实现。 - 八角伸缩:这通常意味着八个方向的大小调整(上、下、左、右、左上、右上、左下、右下)。ElementUI 的 el-dialog 默认不支持这个,可能需要自定义。 我需要提供一个实现案例。步骤包括: 1. 创建一个 Vue 组件。 2. 使用 el-dialog。 3. 实现拖拽功能:参考引用[2],通过 ref 获取 dialog 元素,添加事件监听。 4. 实现八角伸缩:这需要添加自定义元素(如小三角或手柄)在弹框的角落,并监听这些元素的 mousedown 事件来调整大小。 结构清晰的回答: - 介绍问题。 - 逐步实现: - 设置基本 el-dialog- 添加拖拽功能。 - 添加八角伸缩功能。 - 提供完整代码示例。 - 生成相关问题。 生成相关问题:在回答末尾,添加相关问题,如优化、兼容性等。 引用标识:如果我在回答中引用用户提供的引用,需要在末尾添加 [^1]、[^2] 等。 用户提供的引用: - [^1]: 关于添加拖拽功能。 - [^2]: 实现拖拽的具体方法。 - [^3]: el-dialog 的基本结构。 在回答中,我应该基于这些引用构建解决方案。 实现步骤: 1. **基本 el-dialog 设置**:使用引用[3]的代码作为基础。 2. **拖拽功能**:参考引用[2],添加 ref="dialogRef",在 mounted 中添加事件监听。 3. **八角伸缩**:这需要自定义。我需要在弹框的八个角落添加小元素(div),并监听它们的 mousedown 事件来调整宽度和高度。 详细代码: - 拖拽:当鼠标在标题栏按下时,开始拖拽,记录初始位置,监听 mousemove 来移动弹框。 - 伸缩:当鼠标在角落元素按下时,开始调整大小,监听 mousemove 来改变弹框的大小。 完整代码示例: ```vue <template> <div> <el-button @click="dialogVisible = true">打开弹窗</el-button> <el-dialog ref="dialogRef" title="可拖拽伸缩弹窗" :visible.sync="dialogVisible" :modal="false" :close-on-click-modal="false" custom-class="custom-dialog" > <div class="dialog-content"> <!-- 内容 --> <p>这是一个可拖拽伸缩弹窗。</p> </div> <!-- 添加八个角落伸缩手柄 --> <div v-for="corner in corners" :key="corner" :class="['resize-handle', corner]" @mousedown="startResize($event, corner)"></div> </el-dialog> </div> </template> <script> export default { data() { return { dialogVisible: false, isDragging: false, dragOffset: { x: 0, y: 0 }, isResizing: false, resizeCorner: '', startSize: { width: 0, height: 0 }, startPosition: { x: 0, y: 0 }, corners: ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top', 'bottom', 'left', 'right'] // 八个方向 }; }, mounted() { this.initDrag(); }, methods: { initDrag() { const dialog = this.$refs.dialogRef; const header = dialog.$el.querySelector('.el-dialog__header'); if (header) { header.addEventListener('mousedown', this.startDrag); } }, startDrag(e) { if (e.target.className !== 'el-dialog__header') return; // 确保只在标题栏拖动 this.isDragging = true; const dialog = this.$refs.dialogRef.$el; const rect = dialog.getBoundingClientRect(); this.dragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top }; document.addEventListener('mousemove', this.onDrag); document.addEventListener('mouseup', this.stopDrag); }, onDrag(e) { if (!this.isDragging) return; const dialog = this.$refs.dialogRef.$el; dialog.style.position = 'fixed'; dialog.style.left = (e.clientX - this.dragOffset.x) + 'px'; dialog.style.top = (e.clientY - this.dragOffset.y) + 'px'; }, stopDrag() { this.isDragging = false; document.removeEventListener('mousemove', this.onDrag); document.removeEventListener('mouseup', this.stopDrag); }, startResize(e, corner) { this.isResizing = true; this.resizeCorner = corner; const dialog = this.$refs.dialogRef.$el; const rect = dialog.getBoundingClientRect(); this.startSize = { width: rect.width, height: rect.height }; this.startPosition = { x: e.clientX, y: e.clientY }; document.addEventListener('mousemove', this.onResize); document.addEventListener('mouseup', this.stopResize); }, onResize(e) { if (!this.isResizing) return; const dialog = this.$refs.dialogRef.$el; const deltaX = e.clientX - this.startPosition.x; const deltaY = e.clientY - this.startPosition.y; let newWidth = this.startSize.width; let newHeight = this.startSize.height; switch (this.resizeCorner) { case 'top-left': newWidth -= deltaX; newHeight -= deltaY; dialog.style.width = newWidth + 'px'; dialog.style.height = newHeight + 'px'; dialog.style.left = (parseInt(dialog.style.left) || 0) + deltaX + 'px'; dialog.style.top = (parseInt(dialog.style.top) || 0) + deltaY + 'px'; break; case 'top-right': newWidth += deltaX; newHeight -= deltaY; dialog.style.width = newWidth + 'px'; dialog.style.height = newHeight + 'px'; dialog.style.top = (parseInt(dialog.style.top) || 0) + deltaY + 'px'; break; case 'bottom-left': newWidth -= deltaX; newHeight += deltaY; dialog.style.width = newWidth + 'px'; dialog.style.height = newHeight + 'px'; dialog.style.left = (parseInt(dialog.style.left) || 0) + deltaX + 'px'; break; case 'bottom-right': newWidth += deltaX; newHeight += deltaY; dialog.style.width = newWidth + 'px'; dialog.style.height = newHeight + 'px'; break; case 'top': newHeight -= deltaY; dialog.style.height = newHeight + 'px'; dialog.style.top = (parseInt(dialog.style.top) || 0) + deltaY + 'px'; break; case 'bottom': newHeight += deltaY; dialog.style.height = newHeight + 'px'; break; case 'left': newWidth -= deltaX; dialog.style.width = newWidth + 'px'; dialog.style.left = (parseInt(dialog.style.left) || 0) + deltaX + 'px'; break; case 'right': newWidth += deltaX; dialog.style.width = newWidth + 'px'; break; } this.startPosition = { x: e.clientX, y: e.clientY }; // 更新位置以连续调整 }, stopResize() { this.isResizing = false; document.removeEventListener('mousemove', this.onResize); document.removeEventListener('mouseup', this.stopResize); } } }; </script> <style scoped> .custom-dialog { position: fixed; /* 确保可以移动 */ } .resize-handle { position: absolute; width: 10px; height: 10px; background: #409EFF; z-index: 1000; } .top-left { top: -5px; left: -5px; cursor: nw-resize; } .top-right { top: -5px; right: -5px; cursor: ne-resize; } .bottom-left { bottom: -5px; left: -5px; cursor: sw-resize; } .bottom-right { bottom: -5px; right: -5px; cursor: se-resize; } .top { top: -5px; left: 50%; transform: translateX(-50%); cursor: n-resize; } .bottom { bottom: -5px; left: 50%; transform: translateX(-50%); cursor: s-resize; } .left { top: 50%; left: -5px; transform: translateY(-50%); cursor: w-resize; } .right { top: 50%; right: -5px; transform: translateY(-50%); cursor: e-resize; } </style> ``` 在代码中: - 拖拽功能通过监听标题栏的 mousedown 事件实现 [^2]。 - 伸缩功能通过添加八个手柄元素并监听它们的 mousedown 事件实现。 - 样式部分定义了手柄的位置和光标样式。 相关问题生成: 1. 如何优化 el-dialog拖拽伸缩性能? 2. 在移动端如何实现类似功能? 3. 如何限制弹窗的最小和最大尺寸? 确保回答使用中文。</think>### 实现 Vue el-dialog 弹窗的八角伸缩拖拽功能 在 Vue 中使用 ElementUI 的 `el-dialog` 实现弹窗的 **拖拽移动** 和 **八角伸缩(8方向大小调整)** 需要自定义事件和样式。以下是完整的实现方案,基于 ElementUI 的弹窗结构和 Vue 的事件机制。 --- #### 核心实现思路 1. **拖拽功能** 通过监听弹窗标题栏的 `mousedown` 事件,结合 `mousemove` 和 `mouseup` 实现位置移动 [^2]。 2. **八角伸缩功能** 在弹窗的 8 个方向(上、下、左、右、左上、右上、左下、右下)添加自定义手柄元素,监听其 `mousedown` 事件调整弹窗尺寸。 --- #### 完整代码实现 ```vue <template> <div> <el-button @click="dialogVisible = true">打开弹窗</el-button> <el-dialog ref="dialogRef" title="可拖拽伸缩弹窗" :visible.sync="dialogVisible" :modal="false" :close-on-click-modal="false" custom-class="custom-dialog" @closed="resetDialog" > <!-- 弹窗内容 --> <div class="dialog-content"> <p>拖拽标题栏移动位置,拖拽角落手柄调整大小</p> <el-input v-model="inputText" placeholder="测试输入框"></el-input> </div> <!-- 8个方向伸缩手柄 --> <div v-for="handle in resizeHandles" :key="handle.position" :class="['resize-handle', handle.position]" @mousedown="startResize($event, handle.position)" ></div> </el-dialog> </div> </template> <script> export default { data() { return { dialogVisible: false, inputText: '', isDragging: false, // 拖拽状态 isResizing: false, // 伸缩状态 dragOffset: { x: 0, y: 0 }, // 拖拽偏移量 startSize: { width: 0, height: 0 }, // 初始尺寸 startPosition: { x: 0, y: 0 }, // 初始位置 resizeDirection: '', // 当前伸缩方向 resizeHandles: [ // 8个手柄配置 { position: 'top-left', cursor: 'nw-resize' }, { position: 'top', cursor: 'n-resize' }, { position: 'top-right', cursor: 'ne-resize' }, { position: 'right', cursor: 'e-resize' }, { position: 'bottom-right', cursor: 'se-resize' }, { position: 'bottom', cursor: 's-resize' }, { position: 'bottom-left', cursor: 'sw-resize' }, { position: 'left', cursor: 'w-resize' } ] }; }, mounted() { this.initDrag(); // 初始化拖拽事件 }, methods: { // 初始化拖拽:监听标题栏事件 initDrag() { const dialog = this.$refs.dialogRef; const header = dialog.$el.querySelector('.el-dialog__header'); if (header) { header.addEventListener('mousedown', this.startDrag); } }, // 开始拖拽 startDrag(e) { if (e.target.className !== 'el-dialog__header') return; // 仅限标题栏 this.isDragging = true; const dialog = this.$refs.dialogRef.$el; const rect = dialog.getBoundingClientRect(); this.dragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top }; document.addEventListener('mousemove', this.onDrag); document.addEventListener('mouseup', this.stopDrag); }, // 拖拽中 onDrag(e) { if (!this.isDragging) return; const dialog = this.$refs.dialogRef.$el; dialog.style.position = 'fixed'; dialog.style.left = (e.clientX - this.dragOffset.x) + 'px'; dialog.style.top = (e.clientY - this.dragOffset.y) + 'px'; }, // 停止拖拽 stopDrag() { this.isDragging = false; document.removeEventListener('mousemove', this.onDrag); document.removeEventListener('mouseup', this.stopDrag); }, // 开始伸缩 startResize(e, direction) { e.stopPropagation(); this.isResizing = true; this.resizeDirection = direction; const dialog = this.$refs.dialogRef.$el; const rect = dialog.getBoundingClientRect(); this.startSize = { width: rect.width, height: rect.height }; this.startPosition = { x: e.clientX, y: e.clientY }; document.addEventListener('mousemove', this.onResize); document.addEventListener('mouseup', this.stopResize); }, // 伸缩中 onResize(e) { if (!this.isResizing) return; const dialog = this.$refs.dialogRef.$el; const deltaX = e.clientX - this.startPosition.x; const deltaY = e.clientY - this.startPosition.y; // 根据方向调整尺寸 switch (this.resizeDirection) { case 'top-left': dialog.style.width = Math.max(200, this.startSize.width - deltaX) + 'px'; dialog.style.height = Math.max(150, this.startSize.height - deltaY) + 'px'; dialog.style.left = (parseInt(dialog.style.left) || 0) + deltaX + 'px'; dialog.style.top = (parseInt(dialog.style.top) || 0) + deltaY + 'px'; break; case 'top': dialog.style.height = Math.max(150, this.startSize.height - deltaY) + 'px'; dialog.style.top = (parseInt(dialog.style.top) || 0) + deltaY + 'px'; break; case 'top-right': dialog.style.width = Math.max(200, this.startSize.width + deltaX) + 'px'; dialog.style.height = Math.max(150, this.startSize.height - deltaY) + 'px'; dialog.style.top = (parseInt(dialog.style.top) || 0) + deltaY + 'px'; break; case 'right': dialog.style.width = Math.max(200, this.startSize.width + deltaX) + 'px'; break; case 'bottom-right': dialog.style.width = Math.max(200, this.startSize.width + deltaX) + 'px'; dialog.style.height = Math.max(150, this.startSize.height + deltaY) + 'px'; break; case 'bottom': dialog.style.height = Math.max(150, this.startSize.height + deltaY) + 'px'; break; case 'bottom-left': dialog.style.width = Math.max(200, this.startSize.width - deltaX) + 'px'; dialog.style.height = Math.max(150, this.startSize.height + deltaY) + 'px'; dialog.style.left = (parseInt(dialog.style.left) || 0) + deltaX + 'px'; break; case 'left': dialog.style.width = Math.max(200, this.startSize.width - deltaX) + 'px'; dialog.style.left = (parseInt(dialog.style.left) || 0) + deltaX + 'px'; break; } }, // 停止伸缩 stopResize() { this.isResizing = false; document.removeEventListener('mousemove', this.onResize); document.removeEventListener('mouseup', this.stopResize); }, // 关闭弹窗时重置样式 resetDialog() { const dialog = this.$refs.dialogRef.$el; dialog.style.position = ''; dialog.style.left = ''; dialog.style.top = ''; dialog.style.width = ''; dialog.style.height = ''; } } }; </script> <style scoped> /* 拖拽标题栏样式 */ .el-dialog__header { cursor: move; /* 显示移动光标 */ user-select: none; /* 防止文字选中 */ } /* 伸缩手柄基础样式 */ .resize-handle { position: absolute; width: 10px; height: 10px; background: #409EFF; border-radius: 50%; z-index: 10000; } /* 手柄位置 */ .top-left { top: -5px; left: -5px; cursor: nw-resize; } .top { top: -5px; left: 50%; transform: translateX(-50%); cursor: n-resize; } .top-right { top: -5px; right: -5px; cursor: ne-resize; } .right { top: 50%; right: -5px; transform: translateY(-50%); cursor: e-resize; } .bottom-right { bottom: -5px; right: -5px; cursor: se-resize; } .bottom { bottom: -5px; left: 50%; transform: translateX(-50%); cursor: s-resize; } .bottom-left { bottom: -5px; left: -5px; cursor: sw-resize; } .left { top: 50%; left: -5px; transform: translateY(-50%); cursor: w-resize; } /* 弹窗内容区域 */ .dialog-content { padding: 20px; } </style> ``` --- ### 关键说明 1. **拖拽实现** - 通过 `el-dialog` 的 `ref` 获取 DOM 元素,监听标题栏的 `mousedown` 事件 [^2]。 - 计算鼠标偏移量动态更新弹窗位置(`left`/`top`)。 2. **八角伸缩** -弹窗周围添加 8 个 `div` 作为伸缩手柄。 - 根据手柄方向(如 `top-left`)计算尺寸变化: - 左上角:同时调整宽度、高度和位置。 - 右侧:仅调整宽度。 - 底部:仅调整高度(其他方向同理)。 3. **注意事项** - 设置 `:modal="false"` 避免遮罩层干扰事件。 - 使用 `Math.max(200, ...)` 限制最小尺寸(可自定义)。 - 关闭弹窗时重置样式,避免位置错乱。 --- ### 效果演示 - **拖拽**:点击标题栏移动弹窗- **伸缩**:拖拽蓝色手柄调整大小(8个方向独立控制)。 - **兼容性**:支持鼠标事件,适用于桌面端。 > 此实现提升了用户交互体验,允许自由调整弹窗位置和尺寸 [^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值