elementUI 弹出框添加可自定义拖拽和拉伸功能,并处理边界问题

开发完后台管理系统的弹出框模块,被添加拖拽和拉伸功能,看了很多网上成熟的帖子引到项目里总有一点问题,下面是根据自己的需求实现的步骤:

首先在vue项目中创建一个js文件eg:dialog.js

  1 import Vue from 'vue'
  2 // v-dialogDrag: 弹窗拖拽属性
  3 Vue.directive('dialogDrag', {
  4   bind (el, binding, vnode, oldVnode) {
     // 自定义属性,判断是否可拖拽 
5 if (!binding.value) return 6 const dialogHeaderEl = el.querySelector('.el-dialog__header') 7 const dragDom = el.querySelector('.el-dialog') 8 dialogHeaderEl.style.cssText += ';cursor:move;' 9 dragDom.style.cssText += ';top:0px;' 10 11 // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); 12 const sty = (function () { 13 if (document.body.currentStyle) { 14 // 在ie下兼容写法 15 return (dom, attr) => dom.currentStyle[attr] 16 } else { 17 return (dom, attr) => getComputedStyle(dom, false)[attr] 18 } 19 })() 20 21 dialogHeaderEl.onmousedown = (e) => { 22 // 鼠标按下,计算当前元素距离可视区的距离 23 const disX = e.clientX - dialogHeaderEl.offsetLeft 24 const disY = e.clientY - dialogHeaderEl.offsetTop 25 26 const screenWidth = document.body.clientWidth // body当前宽度 27 const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度,可某些环境下无法获取) 28 29 const dragDomWidth = dragDom.offsetWidth // 对话框宽度 30 const dragDomheight = dragDom.offsetHeight // 对话框高度 31 32 const minDragDomLeft = dragDom.offsetLeft 33 const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth 34 35 const minDragDomTop = dragDom.offsetTop 36 const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight 37 38 // 获取到的值带px 正则匹配替换 39 let styL = sty(dragDom, 'left')
     // 为兼容ie 
40 if (styL === 'auto') styL = '0px' 41 let styT = sty(dragDom, 'top') 42 43 console.log(styL) 44 // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px 45 if (styL.includes('%')) { 46 styL = +document.body.clientWidth * (+styL.replace(/%/g, '') / 100) 47 styT = +document.body.clientHeight * (+styT.replace(/%/g, '') / 100) 48 } else { 49 styL = +styL.replace(/px/g, '') 50 styT = +styT.replace(/px/g, '') 51 }; 52 53 document.onmousemove = function (e) { 54 55 // 通过事件委托,计算移动的距离 56 let left = e.clientX - disX 57 let top = e.clientY - disY 58 // 边界处理 59 if (-(left) > minDragDomLeft) { 60 left = -(minDragDomLeft) 61 } else if (left > maxDragDomLeft) { 62 left = maxDragDomLeft 63 } 64 65 if (-(top) > minDragDomTop) { 66 top = -(minDragDomTop) 67 } else if (top > maxDragDomTop) { 68 top = maxDragDomTop 69 } 70 71 // 移动当前元素 72 dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;` 73 } 74 75 document.onmouseup = function (e) { 76 document.onmousemove = null 77 document.onmouseup = null 78 } 79 return false 80 } 81 } 82 }) 83 84 Vue.directive('dialogChange', { 85 bind (el, binding, vnode, oldVnode) {
     // 自定义属性,判断是否可拉伸
86 if (!binding.value) return 87 const dragDom = el.querySelector('.el-dialog') 88 let dragMouse 89 // 在弹出框的右下角添加可拉伸标志 class='mouse' 95 for (let i = 0; i < dragDom.childNodes[2].childNodes.length; i++) { 96 if (dragDom.childNodes[2].childNodes[i].className === 'mouse') { 97 dragMouse = dragDom.childNodes[2].childNodes[i] 98 } 99 } 100 // 鼠标拖拽 101 dragMouse.onmousedown = (e) => { 102 // content区域 103 const content = dragDom.parentNode.parentNode.parentNode.parentNode 104 const disX = e.clientX - dragDom.offsetWidth 105 const disY = e.clientY - dragDom.offsetHeight 106 107 document.onmousemove = function (e) { 108 e.preventDefault() // 移动时禁用默认事件 109 // 通过事件委托,计算移动的距离 110 let width = e.clientX - disX 111 let height = e.clientY - disY 112 113 if (width > content.offsetWidth && height < content.offsetHeight) { 114 dragDom.style.height = `${height}px` 115 } else if (width < content.offsetWidth && height > content.offsetHeight) { 116 dragDom.style.width = `${width}px` 117 } else if (width < content.offsetWidth && height < content.offsetHeight) { 118 dragDom.style.width = `${width}px` 119 dragDom.style.height = `${height}px` 120 } 121 } 122 document.onmouseup = function (e) { 123 document.onmousemove = null 124 document.onmouseup = null 125 } 126 return false 127 } 128 } 129 })

在main.js中引用

import './components/dialog'

dialog组件 代码中添加v-if为了让每次弹出框都不继承上一次的改变:

 1     <el-dialog
 2         v-if=dialog.dialogVisible
 3         v-dialogDrag:{dialogDrag}=dialog.dialogDrag
 4         v-dialogChange:{dialogChange}=dialog.dialogChange
 5         ref="dialog__wrapper"
 6         :close-on-click-modal="false"
 7         :title=dialog.title
 8         :visible.sync="dialog.dialogVisible"
 9         :before-close="handleClose">
10         <div class="dialog-body">
11           <div class="line">
12             <slot name="content"></slot>
13           </div>
14         </div>
15         <slot slot="footer" class="dialog-footer"></slot>
16       </el-dialog>

在引用组件时, data返回一个:

    dialog: {// dialog显示隐藏
        dialogVisible: false,
        dialogDrag: true, // 可拖拽
        dialogChange: true, // 可拉伸
        title: '详情'
      }

 

转载于:https://www.cnblogs.com/Lu-Lu/p/11168904.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值