开始学习前端,最先就是想着实现拖动的效果,也是实现了,但一直存在这在快速拖动的情况下,鼠标会一次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 创建