ModalDragMixins.js
4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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]
}