动态HTML创作之八(鼠标拖放) |
| 让我们再次回到鼠标。拖放概念是彻底地基于鼠标事件的。就像可以捕捉键盘事件一样去捕捉鼠标事件,比如“onMouseDown(按下鼠标键)”、“onMouseUp(释放鼠标键)”和“onMouseMove(移动鼠标)”等。
初始化鼠标事件 所有的鼠标事件“onMouseDown”、“onMouseUp”和“onMouseMove”都用一种方法来初始化: function init() {//从BODY onLoad开始调用 document.onmousedown=mouseDown document.onmousemove=mouseMove document.onmouseup=mouseUp if(ns4) document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP) } function mouseDown(e) { } function mouseMove(e) { } function mouseUp(e) { } 函数名可以随意取,但是不管怎样,应该取一些容易被理解的名字如“mouseDown(e)”、“mouseMove(e)”和“mouseUp(e)”。 对于Netscape来说,“e”代表内建事件对象。可以独得当前位置: var x=e.pageX var y=e.pageY 当Internet Explorer读取这些代码时,将忽略这些“e”。 对于Internet Explorer,窗口包含一个事件对象,可以使用“window.event”来访问它。在鼠标事件发生的地方,“window.event”对象包含代表位置的x和y值: var x=event.x var y=event.y 当鼠标事件发生时,IE的浏览器会特别地反应出值,但是这并不真正反应实际文档的情况,当向下滚屏时,“window.event.y”的值并不与文档同步增加,因些在设计时不得不考虑进行调整,可以使用“document.body.scrollTop”来为滚屏文档加上数值。 var x=event.x+document.body.scrollLeft var y=event.y+document.body.scrollTop 然后,可以把一小块代码加入来适应不同的浏览器: if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} 这些代码可以插入每一个鼠标函数中: function mouseDown(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} } function mouseMove(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} } function mouseUp(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} } 对此,鼠标的初始化都完成了,而且对于IE和Netscape之间的不同之处也做了特别的处理,于是可以分别对三个鼠标事件进行介绍。 “mouseDown()”事件 现在要让鼠标做一个简单的动作来说明问题:当某个人单击鼠标时,把一个层移动到鼠标所在的位置。首先,要初始化层: if(ns4) { dragObj=document.squareDiv dragObj.xpos=dragObj.left dragObj.ypos=dragObj.top } if(ie4) { dragObj=squareDiv.style dragObj.xpos=dragObj.pixelLeft dragObj.ypos=dragObj.pixelTop } 然后,使用<DIV>标记建立一个层。于是在“mouseDown()”函数里,使用x和y变量来把刚才建立的层移动到那个值的位置: function mouseDown(e) { if(ns4 && e.which==1) || ie4) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} dragObj.xpos=x dragObj.ypos=y dragObj.left=dragObj.xpos dragObj.top=dragObj.ypos } } 或者,为了增加趣味性,在移动的同时把鼠标的位置显示在浏览器的“状态栏”里: function mouseMove(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} status="x:"+x+"y:"+y } 完整的“mouseDown()”事件例子如下,当用户在页面任意一点上单击后,事先建立的层就会移动到鼠标所在的位置。 <HTML> <HEAD> <TITLE>DHTML Demo</TITLE> <script language="javascript"> <!-- ns4=(document.layers)?true:false ie4=(document.all)?true:false function init() { if(ns4) { dragObj=document.squareDiv dragObj.xpos=dragObj.left dragObj.ypos=dragObj.top } if(ie4) { dragObj=squareDiv.style dragObj.xpos=dragObj.pixelLeft dragObj.ypos=dragObj.pixelTop } document.onmousedown=mouseDown document.onmousemove=mouseMove document.onmouseup=mouseUp if(ns4) document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP) } function mouseDown(e) { if((ns4 && e.which==1) || ie4) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} dragObj.xpos=x dragObj.ypos=y dragObj.left=dragObj.xpos dragObj.top=dragObj.ypos } } function mouseMove(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} status="x:"+x+"y:"+y } function mouseUp(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} } //--> </script> <style type="text/css"> <!-- #squareDiv{position:absolute;left:100;top:100;width:50;height:50;clip:rect(0,50,50,0); background-color:blue;layer-background-color:blue;} --> </style> </HEAD> <BODY onLoad="init()"> <div id="instructions" style="position:absolute;"> <p>在页面上任意地点单击鼠标,方块就会移动到那一点。</p> </div><div id="squareDiv"></div> </BODY> </HTML> “mouseMove()”事件 不像“mouseDown()”或“mouseUp()”事件,“mouseMove()”函数在鼠标移动的时候总激活的。但是我们并不总是要在鼠标移动的时候做其他事件。比如,在拖动的时候,我们仅仅要在鼠标单击之后才激活鼠标移动的事件。因此,要得到对“mouseMove”事件更多的控制权,可以使用活动变量“dragActive”: dragActive=false//初始时不激活 然后在“mouseDown()”函数中,先不让层移动到鼠标所在的位置上,而是把“mouseMoveActive”变量值设置为1(true): function mouseDown(e) { if((ns4 && e.which==1) || ie4) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} dragActive=true } } 然后再让“mouseMove”来做所有的事情。现在鼠标每次移动时,层总是跟随着鼠标的位置: function mouseMove(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} status="x:"+x+"y:"+y if(dragActive){ dragObj.xpos=x dragObj.ypos=y dragObj.left=dragObj.xpos dragObj.top=dragObj.ypos return false } } 上面的代码中加入了一个附加的命令:“return false”。这是很重要的,因为它避免了一个Netscape会出现的问题。这个问题发生在当把一张图片放在CSS层中,如果不是按照上面的做法,不返回“false”,拖放动作将被中止。这里有一个完整的鼠标移动事件例子: <HTML> <HEAD> <TITLE>DHTML Demo</TITLE> <script language="javascript"> <!-- ns4=(document.layers)?true:false ie4=(document.all)?true:false function init() { if(ns4) { dragObj=document.squareDiv dragObj.xpos=dragObj.left dragObj.ypos=dragObj.top } if(ie4) { dragObj=squareDiv.style dragObj.xpos=dragObj.pixelLeft dragObj.ypos=dragObj.pixelTop } dragActive=false document.onmousedown=mouseDown document.onmousemove=mouseMove document.onmouseup=mouseUp if(ns4) document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP) } function mouseDown(e) { if((ns4 && e.which==1) || ie4) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} dragActive=true } } function mouseMove(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} if(dragActive) { dragObj.xpos=x dragObj.ypos=y dragObj.left=dragObj.xpos dragObj.top=dragObj.ypos return false } } function mouseUp(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} } //--> </script> <style type="text/css"> <!-- #squareDiv{position:absolute;left:100;top:100;width:50;height:50;clip:rect(0,50,50,0); background-color:blue;layer-background-color:blue;} --> </style> </HEAD> <BODY onLoad="init()"> <div id="instructions" style="position:absolute;"> <p>当你在页面上单击后,方块就会跟随鼠标一起移动。</p></div> <div id="squareDiv"></div> </BODY> </HTML> 只要实践一下就一定会发现这个例子其实有一个致命的缺陷。解决这个缺陷的方法我们将在下面的内容中讨论。 “mouseUp()”事件 在上一个例子中,一旦单击了那个对象,便无法把它放下来,要改变这种情况,可以使用我们所要介绍的最后一项鼠标事件“mouseUp”来把“mouseMoveActive”变量设置为0,使“mouseMove”无效: function mouseUp(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} dragActive=false } 为此,我们可以使鼠标在释放时,对象就脱离鼠标的控制,完整的程序如下: <HTML> <HEAD> <TITLE>DHTML Demo</TITLE> <script language="javascript"> <!-- ns4=(document.layers)?true:false ie4=(document.all)?true:false function init() { if(ns4) { dragObj=document.squareDiv dragObj.xpos=dragObj.left dragObj.ypos=dragObj.top } if(ie4) { dragObj=squareDiv.style dragObj.xpos=dragObj.pixelLeft dragObj.ypos=dragObj.pixelTop } dragActive=false document.onmousedown=mouseDown document.onmousemove=mouseMove document.onmouseup=mouseUp if(ns4) document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP) } function mouseDown(e) { if((ns4 && e.which==1) || ie4) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} dragClickX=x-dragObj.xpos dragClickY=y-dragObj.ypos dragActive=true } } function mouseMove(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} if(dragActive) { dragObj.xpos=x-dragClickX dragObj.ypos=y-dragClickY dragObj.left=dragObj.xpos dragObj.top=dragObj.ypos return false } } function mouseUp(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x;var y=event.y+document.body.scrollTop} dragActive=false } //--> </script> <style type="text/css"> <!-- #squareDiv{position:absolute;left:100;top:100;width:50;height:50;clip:rect(0,50,50,0); background-color:blue;layer-background-color:blue;} --> </style> </HEAD> <BODY onLoad="init()"> <div id="instructions" style="position:absolute;"> 无论你单击页面的何处,方块都会感应到。 <br>当你按下鼠标左键时可以任意拖动方块。 <br>当你释放鼠标后,方块同时也会停止移动。 </div> <div id="squareDiv"></div> </BODY> </HTML> 完美的鼠标拖放 我们已经非常接近成功了!可以看出,上面例子的唯一缺憾就是无论单击页面的什么位置,方块都会跟着移动,如果页面只有一个层,那么问题还不是很大,但是如果有多个层,你一定会被搞糊涂,于是我们想到,应该让方块只有鼠标点击到它上面的情况下,才开始跟随鼠标移动。这种效果已经和Windows中的拖放几乎一样了。 我们可以使用另外一个“mouseDown”函数来检查是否单击在层的上面。 其中最普通的方法就是比较鼠标和层的位置,需要获取层边缘的数值。 在Netscape里,宽度和高度是基于剪切宽度和剪切高度的值: document.layername.clip.width document.layername.clip.height 在Internet Explorer里,必须使用“pixelWidth”和“pixelHeight”: layernames.style.pixelWidth layernames.style.pixelHeight 因此程序的初始化代码可以替换为包含这些值的“w”和“h”属性: if(ns4) { dragObj=document.squareDiv dragObj.xpos=dragObj.left dragObj.ypos=dragObj.top dragObj.w=dragObj.clip.width dragObj.h=dragObj.clip.width } if(ie4) { dragObj=squareDiv.style dragObj.xpos=dragObj.pixelLeft dragObj.ypos=dragObj.pixelTop dragObj.w=dragObj.pixelWidth dragObj.h=dragObj.pixelHeight } 于是,使用每一个属性令我们能够设置一个在范围的“if”语句来检验用户是否在层的边框范围内单击过: if(x>=dragObj.xpos && x<=dragObj.xpos+dragObj.w && y>=dragObj.ypos && y<=dragObj.ypos+dragObj.h) 这一行被插入“mouseDown()”函数来确定用户仅仅在层被单击的情况下才激活拖动事件。 注意:必须在一旦开始拖动后马上在“onMouseDown”中放入一个返回“false”值,这可以避免在Mac机器上产生问题。 我们终于成功地完成了鼠标拖动事件的设计,现在完整地演示一遍吧: <HTML> <HEAD> <TITLE>DHTML Demo</TITLE> <script language="javascript"> <!-- ns4=(document.layers)?true:false ie4=(document.all)?true:false function init() { if(ns4) { dragObj=document.squareDiv dragObj.xpos=dragObj.left dragObj.ypos=dragObj.top dragObj.w=dragObj.clip.width dragObj.h=dragObj.clip.width } if(ie4) { dragObj=squareDiv.style dragObj.xpos=dragObj.pixelLeft dragObj.ypos=dragObj.pixelTop dragObj.w=dragObj.pixelWidth dragObj.h=dragObj.pixelHeight } dragActive=false document.onmousedown=mouseDown document.onmousemove=mouseMove document.onmouseup=mouseUp if(ns4) document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP) } function mouseDown(e) { if((ns4 && e.which==1) || ie4) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x+document.body.scrollLeft;var y=event.y+document.body.scrollTop} if(x>=dragObj.xpos && x<=dragObj.xpos+dragObj.w && y>=dragObj.ypos && y<=dragObj.ypos+dragObj.h) { dragClickX=x-dragObj.xpos dragClickY=y-dragObj.ypos dragActive=true return false } } } function mouseMove(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x+document.body.scrollLeft;var y=event.y+document.body.scrollTop} if(dragActive) { dragObj.xpos=x-dragClickX dragObj.ypos=y-dragClickY dragObj.left=dragObj.xpos dragObj.top=dragObj.ypos return false } } function mouseUp(e) { if(ns4) {var x=e.pageX;var y=e.pageY} if(ie4) {var x=event.x+document.body.scrollLeft;var y=event.y+document.body.scrollTop} dragActive=false } //--> </script> <style type="text/css"> <!-- #squareDiv{position:absolute;left:100;top:100;width:50;height:50;clip:rect(0,50,50,0); background-color:blue;layer-background-color:blue;} --> </style> </HEAD> <BODY onLoad="init()"> <div id="instructions" style="position:absolute;"> <p>无论你单击页面的何处,方块都会感应到。 <br>当你按下鼠标键不放时可以任意拖动方块。 <br>当你释放鼠标后,就把方块放置在当前的地方。 </p> </div> <div id="squareDiv"></div> </BODY> </HTML> |