Commit cef39724ec9e190ce956054a2bbb5fe32a3eba55
1 parent
5ac17e91
弹窗model,支持拖动位置
Showing
2 changed files
with
172 additions
and
1 deletions
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 | +} | |
... | ... |