功能实现之拖拽及其脱离的解决方案

开始学习前端,最先就是想着实现拖动的效果,也是实现了,但一直存在这在快速拖动的情况下,鼠标会一次move超出拖动对象的范围,导致对象脱离,然后鼠标返回对象就会默认一直再拖。今天突然想到了办法,在这里写下来便于理解、记忆。


拖拽实现的方法

拖拽可分为三步:选取,拖动,放下。

这就对应了鼠标的三个事件:鼠标按下(mousedown),鼠标移动(mousemove),鼠标放起(mouseup)。

鼠标按下(mousedown)

我们使用一个变量来标记是否按下,当鼠标按下后,使这个标记变为一个值标记为已按下的状态。同时记录下点击时鼠标相对文本的坐标以及移动前的坐标。

1
2
3
4
5
6
7
8
9
10
11
var startX;
var startY;
var DivstartX;
var DivstartY;
div.addEventListener("mousedown",function(e){
draging=true;
startX=e.clientX;
startY=e.clientY;
DivstartX=div.style.left;
DivstartY=div.style.top;
});

鼠标放起(mouseup)

在鼠标放起后,将这个标记重置为按下的状态。

1
2
3
div.addEventListener("mouseup",function(e){
draging=false;
});

鼠标移动(mousemove)

拖拽的核心功能就是移动,如果所以我们需要移动,那么我们可通过设在对象的style的top和left来实现位置的改变。同时检测鼠标的坐标与之前的坐标对比,可以根据差别获取新的的坐标数据。

1
2
3
4
5
6
div.addEventListener("mousemove",function(e){
if(draging){
div.style.left=DivstartX+e.clientX-startX+'px';
div.style.top=DivstartY+e.clientY-startY+'px';
}
});

我们就可以快速的根据这三个函数实现一个简单的拖拽功能。如下是一个简单的DEMO的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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style media="screen">
div{
width: 100px;
height: 100px;
position: absolute;
background-color: red;
}
</style>
</head>
<body>
<div id="dragEx" style="left:100px;top:100px"></div>
<script type="text/javascript">
var div=document.getElementById("dragEx");
var draging=false;
var startX;
var startY;
var DivstartX;
var DivstartY;
div.addEventListener("mousedown",function(e){
draging=true;
startX=e.clientX;
startY=e.clientY;
DivstartX=div.offsetLeft;
DivstartY=div.offsetTop;
});
div.addEventListener("mouseup",function(){
draging=false;
});
div.addEventListener("mousemove",function(e){
if(draging){
div.style.left=DivstartX+e.clientX-startX+'px';
div.style.top=DivstartY+e.clientY-startY+'px';
}
});
</script>
</body>
</html>

脱离的解决方法以及优化

上面的代码虽然实现了拖拽功能,但是当你快速拖动时,鼠标一次性移出拖拽对象的范围就会出现bug,下面讲解,我想到的解决方法。以后有新的想法或解决方案也会在这里列出。

方法一:将move的监听放到document

鼠标一次性移出拖拽对象的范围出现bug,这是原因,那么我们将拖拽监听的对象,不设为本身,将监听的时间放到document全局,那么就不存在脱离了,除非你的鼠标跑出了浏览器显示的地方。

但是如果我们直接将事件永远绑定到document里面将会一直占用资源,特别是鼠标移动这个事件在document是最常触发的。所以我们可以在点击后才添加监听事件,收起后取消监听。这样我们还可以少一个标记是否在拖拽的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var startX;
var startY;
var DivstartX;
var DivstartY;
div.addEventListener("mousedown",function(e){
startX=e.clientX;
startY=e.clientY;
DivstartX=div.offsetLeft;
DivstartY=div.offsetTop;
document.addEventListener("mousemove",move);
});
div.addEventListener("mouseup",function(){
document.removeEventListener("mousemove",move);
});
function move(e){
div.style.left=DivstartX+e.clientX-startX+'px';
div.style.top=DivstartY+e.clientY-startY+'px';
}

改进二:将移动,收起等时间添加到点击事件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var startX;
var startY;
var DivstartX;
var DivstartY;
div.addEventListener("mousedown",function(e){
startX=e.clientX;
startY=e.clientY;
DivstartX=div.offsetLeft;
DivstartY=div.offsetTop;
document.addEventListener("mouseup",up);
document.addEventListener("mousemove",move);
function move(e){
div.style.left=DivstartX+e.clientX-startX+'px';
div.style.top=DivstartY+e.clientY-startY+'px';
}
function up(){
document.removeEventListener("mousemove",move);
document.removeEventListener("mouseup",up);
}
});

这样后就可以肆意的拖拽啦~~!

END

2016-11-17 添加改进二

2016-10-01 创建