開發完后台管理系統的彈出框模塊,被添加拖拽和拉伸功能,看了很多網上成熟的帖子引到項目里總有一點問題,下面是根據自己的需求實現的步驟:
首先在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: '詳情' }