使用 Javascript 进行拖放






3.64/5 (7投票s)
2007年8月30日
3分钟阅读

60286

641
本文介绍了一种在 HTML 页面中拖放元素的方法
引言
随着人们推动以用户为中心的发展,拖放功能只是在强调以用户为中心开发的网页中常见的功能之一。本文讨论了一种实现这种功能的方法,同时考虑到浏览器兼容性的问题。
使用代码
我为此使用了面向对象的方法(当然也可以在没有面向对象的情况下完成)。负责拖放的主要类是 Drag。我们只需要调用 Init() 函数即可启动它。它的作用是确定浏览器的类型并设置相应的变量。
说到拖放,我首先想到的是
- 鼠标按键按下,
- 鼠标移动,
- 鼠标按键抬起。
我们将通过检索鼠标的当前 (x,y) 坐标并设置元素的 left,top 属性来控制“元素”的位置。
类声明
function Drag() { this.id="" this.beginDrag="" this.browserType="" this.eventObj="" this.bodyID="" Drag.prototype.SetBrowserType=SetBrowserType Drag.prototype.Init=InitDragClass Drag.prototype.GetBrowserType=GetBrowserType Drag.prototype.BeginDrag=BeginDrag Drag.prototype.GetDragState=GetDragState Drag.prototype.EndDrag=EndDrag Drag.prototype.GetCurrentCoOrdinates=GetCurrentCoOrdinates Drag.prototype.Move=Move Drag.prototype.SetId=SetId Drag.prototype.GetId=GetId Drag.prototype.SetEventObj=SetEventObj Drag.prototype.GetEventObj=GetEventObj Drag.prototype.RemoveChild=RemoveChild } function Position() { this.x="" this.y="" }
不要被函数数量吓倒,它们中的大多数只是 getter 和 setter,而且不言自明。以下是一些需要解释的:
this.id
-> 这将保存我们要拖动的“元素”的 id。this.eventObj
-> 考虑到跨浏览器差异,我使用 'eventObj' 来表示不同浏览器的 'event' 对象。this.beginDrag
-> 这是一个标志,用于指示拖动操作的状态。
function Move(obj,pos) { obj.style.position="absolute" obj.style.zIndex="999" obj.style.left=pos.x+"px" obj.style.top=pos.y+"px" } function GetCurrentCoOrdinates() { var pos=new Position() if(this.GetBrowserType()=="MOZILLA") { pos.x=(typeof this.GetEventObj().pageX =="undefined") ? 0 : this.GetEventObj().pageX pos.y=(typeof this.GetEventObj().pageY =="undefined") ? 0 : this.GetEventObj().pageY } else if(this.GetBrowserType()=="IE") { pos.x=(this.GetEventObj().x < 0 || typeof this.GetEventObj().x=="undefined")? 0 : this.GetEventObj().x pos.y=(this.GetEventObj().y < 0 || typeof this.GetEventObj().y=="undefined")? 0 : this.GetEventObj().y } return pos } function RemoveChild() { try { var obj=document.getElementById(this.GetId()) var objParent=obj.offsetParent var objBody=document.getElementById(this.bodyID) objParent.removeChild(obj) objBody.appendChild(obj) } catch(err) { } }
如类声明所示,Move() 负责实际移动相关元素。GetCurrentCoOrdinates() 如其名称所示,返回 Position 对象。我不会解释其余函数的实现,因为它们的名称暗示了它们的功能,并且它们包含在示例源代码中。
RemoveChild 是一个错误修复。在此之前,元素受其父元素的区域限制(它们无法超出其父元素的区域向左移动)。为了解决这个问题,我从父元素中删除目标元素,并将其附加到页面的 body 中。body 拥有整个页面区域。仍然存在旧的限制,但由于 body 是页面,我们不会遇到这种限制。并且由于我们将其附加到 body,因此我们需要给 body 一个 id。我在调用 Init() 时设置了 id。
我们需要处理 onmousedown、onmousemove、onmouseup 事件,我们需要明确指定我们对此感兴趣。
document.onmousemove=function(e) //e for Mozilla Firefox { HandleMouseMove(e) } document.onmouseup=function(e) { if(dragObj.GetId()!=null && dragObj.beginDrag==true) { HandleMouseUp(dragObj.GetId()) } }
注意:Internet Explorer 中似乎存在一个错误,因为它没有在“element”的声明中调用“onmouseup”事件,所以我不得不明确地写下来。为了处理鼠标按下事件,我使用了函数 HandleMouseDown(id)。
function HandleMouseUp(id) { dragObj.EndDrag() //set the beginDrag flag to false dragObj.SetId("") //clear the id, since we stopped dragging the 'element' } function HandleMouseDown(id) { dragObj.BeginDrag() //set the beginDrag flag to true dragObj.SetId(id) //set the id to denote the 'element' we are interested to drag. } function HandleMouseMove(eventObj) //this would accept the parameter for event, which is a local object for Firefox. { //Since it is a global object in Internet Explorer, we don't have to worry about it. if(typeof eventObj!="undefined") //this means browser is Firefox { if(dragObj.GetId()!=null && dragObj.beginDrag==true) { dragObj.SetEventObj(eventObj) dragObj.RemoveChild() dragObj.Move(document.getElementById(dragObj.GetId()),dragObj.GetCurrentCoOrdinates()) } } else //this means browser is Internet Explorer { if(dragObj.GetId()!=null && dragObj.beginDrag==true) { dragObj.SetEventObj(event) dragObj.RemoveChild() dragObj.Move(document.getElementById(dragObj.GetId()),dragObj.GetCurrentCoOrdinates()) } } }
当拖动结束时,zIndex 将被设置回 null。设置 zIndex 会将相关元素置于前景。最后,您需要在声明元素时添加这段代码
onmousedown="javascript:HandleMouseDown(this.id)" onmouseup="javascript:HandleMouseUp(this.id)" onmousemove="HandleMouseMove(this.id)"
我们现在准备好拖动了。我附上了一个示例供参考。
历史
v 1.0 已添加
v 1.1 错误修复,元素现在不受其父元素区域的限制。