import {getRefPromise} from '@/utils/util' /** JModal 的拖拽混入 */ export default { data() { return { // 拖动配置 dragSettings: { // 上次拖动top记录 top: null, // 上次拖动left记录 left: null, wrapEl: null, dragEl: null, headerEl: null, }, } }, watch: { visible() { if (!this.visible || !this.draggable) { return } this.handleDrag() }, draggable() { if (!this.visible || !this.draggable) { return } this.handleDrag() }, }, methods: { async handleDrag() { let modalRef = await getRefPromise(this, 'modal') const dragWraps = modalRef.$el.querySelectorAll('.ant-modal-wrap') let wrapEl = dragWraps[0] if (!wrapEl) return this.dragSettings.wrapEl = wrapEl this.dragSettings.dragEl = wrapEl.querySelector('.ant-modal') this.dragSettings.headerEl = wrapEl.querySelector('.ant-modal-header') const display = getStyle(wrapEl, 'display') const draggable = wrapEl.getAttribute('data-drag') if (display !== 'none') { // 拖拽位置 if (draggable === null || this.destroyOnClose) { this.enableDrag(wrapEl) } } }, /** 启用拖拽 */ enableDrag() { let {wrapEl, dragEl, headerEl} = this.dragSettings if (!wrapEl) return wrapEl.setAttribute('data-drag', this.draggable) if (!headerEl || !dragEl || !this.draggable) return // 还原上一次移动的位置 this.resetModalPosition() headerEl.style.cursor = 'move' headerEl.onmousedown = (e) => { if (!e) return // 鼠标按下,计算当前元素距离可视区的距离 const disX = e.clientX const disY = e.clientY const screenWidth = document.body.clientWidth // body当前宽度 const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度,可某些环境下无法获取) const dragElWidth = dragEl.offsetWidth // 对话框宽度 const dragElHeight = dragEl.offsetHeight // 对话框高度 const minDragElLeft = dragEl.offsetLeft const maxDragElLeft = screenWidth - dragEl.offsetLeft - dragElWidth const minDragElTop = dragEl.offsetTop const maxDragElTop = screenHeight - dragEl.offsetTop - dragElHeight // 获取到的值带px 正则匹配替换 const domLeft = getStyle(dragEl, 'left') const domTop = getStyle(dragEl, 'top') let styL = +domLeft let styT = +domTop // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px if (domLeft.includes('%')) { styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100) styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100) } else { styL = +domLeft.replace(/px/g, '') styT = +domTop.replace(/px/g, '') } document.onmousemove = (e) => { // 全屏时不触发移动方法 if (this.innerFullscreen) { return } // 通过事件委托,计算移动的距离 let left = e.clientX - disX let top = e.clientY - disY // 边界处理 if (-left > minDragElLeft) { left = -minDragElLeft } else if (left > maxDragElLeft) { left = maxDragElLeft } if (-top > minDragElTop) { top = -minDragElTop } else if (top > maxDragElTop) { top = maxDragElTop } this.setModalPosition(top + styT, left + styL) } document.onmouseup = () => { document.onmousemove = null document.onmouseup = null } } }, /** * 移动弹窗位置 * @param top 顶部位置 * @param left 左侧位置 * @param remember 是否记录位置,默认 true */ setModalPosition(top, left, remember = true) { // 记录移动位置 if (remember) { this.dragSettings.top = top this.dragSettings.left = left } // 移动当前元素 this.dragSettings.dragEl.style.cssText += `;left:${left}px;top:${top}px;` }, /** * 将弹窗移动到上次记录的位置 */ resetModalPosition() { this.setModalPosition(this.dragSettings.top, this.dragSettings.left, false) }, }, } function getStyle(dom, attr) { return getComputedStyle(dom)[attr] }