-
Notifications
You must be signed in to change notification settings - Fork 0
/
拖拽-封装-支持移动端.html
169 lines (150 loc) · 6.13 KB
/
拖拽-封装-支持移动端.html
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#dragparent {
position: relative;
width: 500px;
height: 500px;
border: 1px solid red
}
#dragson {
position: absolute;
width: 100px;
height: 100px;
background-color: blue;
}
</style>
</head>
<body>
<div id="dragparent">
<div id="dragson"></div>
</div>
<script>
class Drag {
constructor(option) {
this.oldX = 0
this.oldY = 0
this.newX = 0
this.newY = 0
this.maxMoveWidth = 0
this.maxMoveHeight = 0
this.isMobile = false
if ('ontouchstart' in window) {
this.isMobile = true
}
this.eventType = {
start: this.isMobile ? 'ontouchstart' : 'onmousedown',
move: this.isMobile ? 'ontouchmove' : 'onmousemove',
end: this.isMobile ? 'ontouchend' : 'onmouseup',
}
if (!option.dragEle) throw '拖拽元素 dragEle 必须传递'
this.dragSon = option.dragEle
if (option.parent) {
this.dragParent = option.parent
this.maxMoveWidth = this.dragParent.clientWidth - this.dragSon.clientWidth
this.maxMoveHeight = this.dragParent.clientHeight - this.dragSon.clientHeight
}
this.init()
}
// 初始化
init() {
// 鼠标按下
this.dragSon[this.eventType['start']] = e => {
// 兼容 IE
let ev = e || window.event
// 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
if (window.event) {
// 兼容 IE
window.event.returnValue = false;
} else {
ev.preventDefault()
}
if (this.isMobile) {
ev = ev.touches[0]
}
// 存储当前鼠标位置
this.oldX = ev.clientX
this.oldY = ev.clientY
this.dragMove()
}
// 鼠标松开
document.documentElement[this.eventType['end']] = e => {
// 函数赋值为 null,让函数失效,便于浏览器垃圾回收
document.documentElement[this.eventType['move']] = null
}
}
// 鼠标移动
dragMove() {
// 因为鼠标移动过快,可能会移出拖拽元素的范围
// 这里使用 document.documentElement.onmousemove 来解决
document.documentElement[this.eventType['move']] = e => {
let ev = e || window.event, endX, endY
// 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
if (window.event) {
// 兼容 IE
window.event.returnValue = false;
} else {
ev.preventDefault()
}
if (this.isMobile) {
ev = ev.touches[0]
}
this.newX = ev.clientX,
this.newY = ev.clientY,
// 拖拽元素 距离 `定位参考父级` 左侧的距离 + `移动鼠标位置 X 轴值` 减去 `之前记录的鼠标位置 X 轴值`
// offsetLeft: 拖拽元素与父级左侧的距离长度(不含父级边框)
endX = this.dragSon.offsetLeft + this.newX - this.oldX,
// 拖拽元素 距离 `定位参考父级` 顶部的距离 + `移动鼠标位置 Y 轴值` 减去 `之前记录的鼠标位置 Y 轴值`
// offsetTop: 拖拽元素与父级顶部的距离长度(不含父级边框)
endY = this.dragSon.offsetTop + this.newY - this.oldY
// 若存在父级,限制在父级范围内移动
if (this.dragParent) {
let { limitEndX, limitEndY } = this.limitRange(endX, endY)
endX = limitEndX
endY = limitEndY
}
// 设置拖拽元素位置
this.dragSon.style.left = endX + 'px'
this.dragSon.style.top = endY + 'px'
// 新旧值交换
this.oldX = this.newX
this.oldY = this.newY
}
}
// 限制移动范围
limitRange(endX, endY) {
// 限制在 定位参考父级元素 内移动
// 左边界
if (endX <= 0) {
endX = 0
}
// 右边界
// X 轴方向可移动距离 = 父级内部宽度 - 拖拽元素宽度
if (endX >= this.maxMoveWidth) {
endX = this.maxMoveWidth
}
// 上边界
if (endY <= 0) {
endY = 0
}
// 下边界
// Y 轴方向可移动距离 = 父级内部高度 - 拖拽元素高度
if (endY >= this.maxMoveHeight) {
endY = this.maxMoveHeight
}
return { limitEndX: endX, limitEndY: endY }
}
}
let dragParent = document.getElementById('dragparent'),
dragSon = document.getElementById('dragson')
new Drag({
parent: dragParent,
dragEle: dragSon
})
</script>
</body>
</html>