EN
JavaScript - how to make drag and drop div with handle?
7 points
Using JavaScript it is possible to make drag&drop div element with handle in the following way.
Note: big advantage of presented approach in this section is resistance for changed margin, border and padding sizes (with nested elements too).
More complicated example with nested elements is here.
xxxxxxxxxx
1
2
<html>
3
<head>
4
<style>
5
6
div.draggable {
7
position: absolute;
8
left: 20px; right: 20px;
9
border: 5px solid gray;
10
}
11
12
div.handle {
13
padding: 3px;
14
position: absolute;
15
left: 0; top: 0; right: 0;
16
background: gold;
17
height: 25px;
18
}
19
20
div.body {
21
padding: 3px;
22
position: absolute;
23
left: 0; top: 25px; right: 0; bottom: 0;
24
background: cyan;
25
/* this style disables elements selection when user is dragging */
26
touch-callout: none; /* iOS Safari */
27
user-select: none; /* Safari */
28
user-select: none; /* Konqueror HTML */
29
user-select: none; /* Firefox in the past (old versions) */
30
user-select: none; /* Internet Explorer (>=10) / Edge */
31
user-select: none; /* Currently supported: */
32
/* Chrome, Opera and Firefox */
33
}
34
35
</style>
36
<script type="text/javascript">
37
38
function computeMargins(element) {
39
var style = element.currentStyle || window.getComputedStyle(element);
40
var result = {
41
marginLeft: parseInt(style.marginLeft),
42
marginRight: parseInt(style.marginRight),
43
marginTop: parseInt(style.marginTop),
44
marginBottom: parseInt(style.marginBottom)
45
};
46
return result;
47
}
48
49
function prepareDragging(element, handle) {
50
var dragging = false;
51
var clickX, clickY;
52
var positionX, positionY;
53
var style = element.style;
54
function onMouseDown(e) {
55
clickX = e.clientX;
56
clickY = e.clientY;
57
var margins = computeMargins(element);
58
// this approach prevents against dragging issues when margins have set sizes
59
positionX = element.offsetLeft - margins.marginLeft - margins.marginRight;
60
positionY = element.offsetTop - margins.marginTop - margins.marginBottom;
61
dragging = true;
62
}
63
function onMouseUp(e) {
64
dragging = false;
65
}
66
function onMouseMove(e) {
67
if (dragging) {
68
var x = positionX + e.clientX - clickX;
69
var y = positionY + e.clientY - clickY;
70
style.left = x + 'px';
71
style.top = y + 'px';
72
}
73
}
74
var onTouchStart = function(event) {
75
var touches = event.touches;
76
if (touches.length === 1) {
77
event.preventDefault();
78
var touch = touches[0];
79
onMouseDown({
80
clientX: touch.clientX,
81
clientY: touch.clientY
82
});
83
}
84
};
85
var onTouchEnd = function(event) {
86
var touches = event.touches;
87
if (touches.length === 0) {
88
onMouseUp({});
89
}
90
};
91
var onTouchMove = function(event) {
92
if (dragging) {
93
event.preventDefault();
94
var touches = event.touches;
95
if (touches.length === 1) {
96
var touch = touches[0];
97
onMouseMove({
98
clientX: touch.clientX,
99
clientY: touch.clientY
100
});
101
}
102
}
103
};
104
handle.addEventListener('mousedown', onMouseDown);
105
handle.addEventListener('touchstart', onTouchStart);
106
window.addEventListener('mouseup', onMouseUp);
107
window.addEventListener('touchend', onTouchEnd);
108
window.addEventListener('mousemove', onMouseMove);
109
window.addEventListener('touchmove', onTouchMove);
110
return function() {
111
if (removed) {
112
return;
113
}
114
handle.removeEventListener('mousedown', onMouseDown);
115
handle.removeEventListener('touchstart', onTouchStart);
116
window.removeEventListener('mouseup', onMouseUp);
117
window.removeEventListener('touchend', onTouchEnd);
118
window.removeEventListener('mousemove', onMouseMove);
119
window.removeEventListener('touchmove', onTouchMove);
120
removed = true;
121
};
122
}
123
124
</script>
125
</head>
126
<body style="height: 200px;">
127
<div id="my-element" class="draggable" style="width: 130px; height: 130px;">
128
<div id="my-handle" class="handle">Drag me...</div>
129
<div class="body">Something inside...</div>
130
</div>
131
<script>
132
133
var element = document.querySelector('#my-element');
134
var handle = document.querySelector('#my-handle');
135
136
prepareDragging(element, handle);
137
138
</script>
139
</body>
140
</html>