Commit cef39724ec9e190ce956054a2bbb5fe32a3eba55

Authored by zhangdaiscott
1 parent 5ac17e91

弹窗model,支持拖动位置

ant-design-vue-jeecg/src/components/jeecg/JModal/JModal.vue
... ... @@ -8,7 +8,7 @@
8 8 v-on="$listeners"
9 9 @ok="handleOk"
10 10 @cancel="handleCancel"
11   - destroyOnClose
  11 + :destroyOnClose="destroyOnClose"
12 12 >
13 13  
14 14 <slot></slot>
... ... @@ -49,13 +49,17 @@
49 49  
50 50 import { getClass, getStyle } from '@/utils/props-util'
51 51 import { triggerWindowResizeEvent } from '@/utils/util'
  52 +import ModalDragMixins from './ModalDragMixins'
52 53  
53 54 export default {
54 55 name: 'JModal',
  56 + mixins: [ModalDragMixins],
55 57 props: {
56 58 title: String,
57 59 // 可使用 .sync 修饰符
58 60 visible: Boolean,
  61 + // 是否开启拖拽
  62 + draggable: Boolean,
59 63 // 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
60 64 fullscreen: {
61 65 type: Boolean,
... ... @@ -71,6 +75,11 @@ export default {
71 75 type: Boolean,
72 76 default: true
73 77 },
  78 + // 关闭时销毁弹窗内容
  79 + destroyOnClose: {
  80 + type: Boolean,
  81 + default: true
  82 + },
74 83 },
75 84 data() {
76 85 return {
... ... @@ -162,6 +171,16 @@ export default {
162 171 toggleFullscreen() {
163 172 this.innerFullscreen = !this.innerFullscreen
164 173 triggerWindowResizeEvent()
  174 + // 全屏的时候禁止拖动
  175 + if (this.innerFullscreen) {
  176 + // 还原弹窗的位置为0,0
  177 + this.setModalPosition(0, 0, false)
  178 + this.dragSettings.headerEl.style.cursor = null
  179 + } else {
  180 + // 取消全屏的时候,将弹窗移动到上次记录的位置
  181 + this.resetModalPosition()
  182 + this.dragSettings.headerEl.style.cursor = 'move'
  183 + }
165 184 },
166 185  
167 186 }
... ...
ant-design-vue-jeecg/src/components/jeecg/JModal/ModalDragMixins.js 0 → 100644
  1 +import {getRefPromise} from '@/utils/util'
  2 +
  3 +/** JModal 的拖拽混入 */
  4 +export default {
  5 + data() {
  6 + return {
  7 + // 拖动配置
  8 + dragSettings: {
  9 + // 上次拖动top记录
  10 + top: null,
  11 + // 上次拖动left记录
  12 + left: null,
  13 + wrapEl: null,
  14 + dragEl: null,
  15 + headerEl: null,
  16 + },
  17 + }
  18 + },
  19 + watch: {
  20 + visible() {
  21 + if (!this.visible || !this.draggable) {
  22 + return
  23 + }
  24 + this.handleDrag()
  25 + },
  26 + draggable() {
  27 + if (!this.visible || !this.draggable) {
  28 + return
  29 + }
  30 + this.handleDrag()
  31 + },
  32 + },
  33 + methods: {
  34 + async handleDrag() {
  35 + let modalRef = await getRefPromise(this, 'modal')
  36 + const dragWraps = modalRef.$el.querySelectorAll('.ant-modal-wrap')
  37 + let wrapEl = dragWraps[0]
  38 + if (!wrapEl) return
  39 + this.dragSettings.wrapEl = wrapEl
  40 + this.dragSettings.dragEl = wrapEl.querySelector('.ant-modal')
  41 + this.dragSettings.headerEl = wrapEl.querySelector('.ant-modal-header')
  42 + const display = getStyle(wrapEl, 'display')
  43 + const draggable = wrapEl.getAttribute('data-drag')
  44 + if (display !== 'none') {
  45 + // 拖拽位置
  46 + if (draggable === null || this.destroyOnClose) {
  47 + this.enableDrag(wrapEl)
  48 + }
  49 + }
  50 + },
  51 + /** 启用拖拽 */
  52 + enableDrag() {
  53 + let {wrapEl, dragEl, headerEl} = this.dragSettings
  54 + if (!wrapEl) return
  55 + wrapEl.setAttribute('data-drag', this.draggable)
  56 + if (!headerEl || !dragEl || !this.draggable) return
  57 +
  58 + // 还原上一次移动的位置
  59 + this.resetModalPosition()
  60 +
  61 + headerEl.style.cursor = 'move'
  62 + headerEl.onmousedown = (e) => {
  63 + if (!e) return
  64 + // 鼠标按下,计算当前元素距离可视区的距离
  65 + const disX = e.clientX
  66 + const disY = e.clientY
  67 + const screenWidth = document.body.clientWidth // body当前宽度
  68 + const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度,可某些环境下无法获取)
  69 +
  70 + const dragElWidth = dragEl.offsetWidth // 对话框宽度
  71 + const dragElHeight = dragEl.offsetHeight // 对话框高度
  72 +
  73 + const minDragElLeft = dragEl.offsetLeft
  74 +
  75 + const maxDragElLeft = screenWidth - dragEl.offsetLeft - dragElWidth
  76 + const minDragElTop = dragEl.offsetTop
  77 + const maxDragElTop = screenHeight - dragEl.offsetTop - dragElHeight
  78 + // 获取到的值带px 正则匹配替换
  79 + const domLeft = getStyle(dragEl, 'left')
  80 + const domTop = getStyle(dragEl, 'top')
  81 + let styL = +domLeft
  82 + let styT = +domTop
  83 +
  84 + // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
  85 + if (domLeft.includes('%')) {
  86 + styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100)
  87 + styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100)
  88 + } else {
  89 + styL = +domLeft.replace(/px/g, '')
  90 + styT = +domTop.replace(/px/g, '')
  91 + }
  92 +
  93 + document.onmousemove = (e) => {
  94 + // 全屏时不触发移动方法
  95 + if (this.innerFullscreen) {
  96 + return
  97 + }
  98 + // 通过事件委托,计算移动的距离
  99 + let left = e.clientX - disX
  100 + let top = e.clientY - disY
  101 +
  102 + // 边界处理
  103 + if (-left > minDragElLeft) {
  104 + left = -minDragElLeft
  105 + } else if (left > maxDragElLeft) {
  106 + left = maxDragElLeft
  107 + }
  108 +
  109 + if (-top > minDragElTop) {
  110 + top = -minDragElTop
  111 + } else if (top > maxDragElTop) {
  112 + top = maxDragElTop
  113 + }
  114 +
  115 + this.setModalPosition(top + styT, left + styL)
  116 + }
  117 +
  118 + document.onmouseup = () => {
  119 + document.onmousemove = null
  120 + document.onmouseup = null
  121 + }
  122 + }
  123 + },
  124 +
  125 + /**
  126 + * 移动弹窗位置
  127 + * @param top 顶部位置
  128 + * @param left 左侧位置
  129 + * @param remember 是否记录位置,默认 true
  130 + */
  131 + setModalPosition(top, left, remember = true) {
  132 + // 记录移动位置
  133 + if (remember) {
  134 + this.dragSettings.top = top
  135 + this.dragSettings.left = left
  136 + }
  137 + // 移动当前元素
  138 + this.dragSettings.dragEl.style.cssText += `;left:${left}px;top:${top}px;`
  139 + },
  140 + /**
  141 + * 将弹窗移动到上次记录的位置
  142 + */
  143 + resetModalPosition() {
  144 + this.setModalPosition(this.dragSettings.top, this.dragSettings.left, false)
  145 + },
  146 +
  147 + },
  148 +}
  149 +
  150 +function getStyle(dom, attr) {
  151 + return getComputedStyle(dom)[attr]
  152 +}
... ...