问题
I have managed to implement a simple JavaScript dragging effect to create "panel windows" inside a webpage, in which I can drag the object from any corner or position. I have only used the onmousedown
(to indicate a possible dragging), onmousemove
(to perform dragging) and onmouseup
(to stop dragging) events.
It works well except when I drag the object too near an edge and move the mouse even at a normal speed. When I move the mouse towards an area outside the object, the dragging fails until I move again to the object's area, and I have to click the object to stop dragging it.
It's like the mouse is too fast, but obviously it doesn't happen in native application windows because they are better implemented.
What checks could I add to my current code so it doesn't fail as much? It currently seems to support a little bit of this problem by somehow handling the onmouseout
event, but when it happens the window shakes to return the mouse pointer to the object area, and it doesn't look so good.
JavaScript Simple Dragging Effect
<!doctype html>
<html>
<head>
<title>JavaScript Simple Dragging Effect</title>
<style type="text/css">
.moveableRect {
position:absolute;
width:320px;
height:200px;
background-color:rgba(254, 220, 186, 0.8);
}
</style>
</head>
<body bgcolor="#abcdef">
<span id="span0000" class="moveableRect"><b>Drag Me<hr /></b></span>
<textarea id="txt" cols="40" rows="12"></textarea>
<script>
//Custom variable to indicate that we
//must drag the SPAN:
///
document.getElementById("span0000").myDragFlag = false;
//When we click and hold the mouse down,
//we must activate the dragging process:
///
document.getElementById("span0000").onmousedown = function(e)
{
if(e.button==0)
{
//This is the part of the trick that allows us
//to drag the object from any starting position
//that we click on it:
///
this.startX=(e.pageX-this.offsetLeft);
this.startY=(e.pageY-this.offsetTop);
//This flag indicates that we must drag
//when moving the mouse while the button is pressed:
///
this.myDragFlag=true;
}
};
//When we move the mouse, we must follow
//the mouse cursor around:
///
document.getElementById("span0000").onmousemove = function(e)
{
var bcr=this.getBoundingClientRect();
if(this.myDragFlag)
{
//When we start dragging (moving the mouse
//while the mouse button is pressed)
//we will perform the effect of dragging from any
//initial position in the rectangle:
///
this.style.left = (e.pageX-this.startX)+"px";
this.style.top = (e.pageY-this.startY)+"px";
document.getElementById("txt").value=
"getBoundingClientRect.left="+bcr.left+"\n"+
"getBoundingClientRect.top="+bcr.top+"\n"+
"getBoundingClientRect.width="+bcr.width+"\n"+
"getBoundingClientRect.height="+bcr.height+"\n"+
"getBoundingClientRect.bottom="+bcr.bottom+"\n"+
"getBoundingClientRect.right="+bcr.right+"\n"+
"e.pageX="+e.pageX+"\n"+
"e.pageY="+e.pageY+"\n"+
"this.offsetLeft="+this.offsetLeft+"\n"+
"this.offsetTop="+this.offsetTop+"\n"+
"relatX="+(e.pageX-this.offsetLeft)+"\n"+
"relatY="+(e.pageY-this.offsetTop);
}
};
//When we release the mouse button,
//we must finish the dragging process:
///
document.getElementById("span0000").onmouseup = function(e)
{
if(e.button==0)
this.myDragFlag=false;
};
document.getElementById("span0000").onmouseout = function(e)
{
if(this.myDragFlag==true)
{
//In this code, we basically check that
//when the mouse slips out from the object
//area while we are still dragging, we will
//force moving the object back under the mouse
//pointer. Here we will check from a logical
//edge of 48 pixels, and we will move the object
//back to 90% within those pixels, vertically and/or
//horizontally. It makes look the object shaky
//but at least it is minimally functional:
///
var minEdge=48;
var edgeCorrect=0.90;
var minEdgeCorrect=(minEdge*edgeCorrect)|0;
var bcr=this.getBoundingClientRect();
var bcrw=bcr.width;
var bcrh=bcr.height;
if(this.startX<minEdge)
{
this.style.left = (e.pageX-minEdgeCorrect)+"px";
}
else if(this.startX>bcrw-minEdge)
{
this.style.left = (e.pageX-this.startX+minEdgeCorrect)+"px";
}
if(this.startY<minEdge)
{
this.style.top = (e.pageY-minEdgeCorrect)+"px";
}
else if(this.startY>bcrh-minEdge)
{
this.style.top = (e.pageY-this.startY+minEdgeCorrect)+"px";
}
}
};
</script>
</body>
</html>
回答1:
Your event listener for onmousemove
is placed on the draggable div. So if the mouse goes off of it, the event stops firing. And it goes off while dragging because it fires mousemove events at intervals instead of every pixel.
To fix it, put the mousemove listener on the container.
document.body.onmousemove
And you will probably need to change how you get the coordinates.
There are other ways too I imagine. But that's the easiest.
Edit
Started to doubt myself when I tried to fiddle this but eventually got it working: http://jsfiddle.net/tg33u8mv/3/
document.body.onmousemove = function (e) {
if (myDragFlag) {
var draggable = document.getElementById("span0000");
var bcr = draggable.getBoundingClientRect();
draggable.style.left = (e.pageX - draggable.startX) + "px";
draggable.style.top = (e.pageY - draggable.startY) + "px";
}
};
And I changed myDragFlag
to a scoped variable instead of this.myDragFlag
.
Bonus
In this version I add a class when it is dragging. http://jsfiddle.net/tg33u8mv/4/
The CSS for this class currently disables highlighting, significantly improving the look. You could also make it change color or add a shadow for a nice effect.
来源:https://stackoverflow.com/questions/27450376/improving-javascript-dragging-effect