JavaScript 拖放效果

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

JavaScript拖放效果拖放效果,也叫拖拽、拖动,学名Drag-and-drop,是最常见的js特效之一。如果忽略很多细节,实现起来很简单,但往往细节才是难点所在。这个程序的原型是在做图片切割效果的时候做出来的,那时参考了好几个同类的效果,跟muxrwc和BlueDestiny学习了不少东西。虽然每次整理都觉得很好了,不过每隔一段时间又会发现得某个地方可以改善,某个地方有错误,某些需求需要实现,就像自己学习的知识那样。这里考虑到有的人可能只需要简单的拖放,所以有一个简化版的拖放SimpleDrag,方便学习。效果预览在maxthon下如果开启广告过滤的话很可能会被过滤掉(不知有什么方法可以避免)。拖放状态:结束拖放程序说明【程序原理】这里以SimpleDrag为例说一下基本原理。首先初始化程序中要一个拖放对象:this.Drag=$(drag);还要两个参数在开始时记录鼠标相对拖放对象的坐标:this._x=this._y=0;还有两个事件对象函数用于添加移除事件:this._fM=BindAsEventListener(this,this.Move);this._fS=Bind(this,this.Stop);分别是拖动程序和停止拖动程序。拖放对象的position必须是absolute绝对定位:this.Drag.style.position=absolute;最后把Start开始拖放程序绑定到拖放对象mousedown事件:addEventHandler(this.Drag,mousedown,BindAsEventListener(this,this.Start));鼠标在拖放对象按住,就会触发Start程序,主要是用来准备拖动,在这里记录鼠标相对拖放对象的坐标:this._x=oEvent.clientX-this.Drag.offsetLeft;this._y=oEvent.clientY-this.Drag.offsetTop;并把_fM拖动程序和_fS停止拖动程序分别绑定到document的mousemove和mouseup事件:addEventHandler(document,mousemove,this._fM);addEventHandler(document,mouseup,this._fS);绑定到document可以保证事件在整个窗口文档中都有效。当鼠标在文档上移动时,就会触发Move程序了,这里就是实现拖动的程序。通过现在鼠标的坐标值跟开始拖动时鼠标相对的坐标值的差就可以得到拖放对象应该设置的left和top了:this.Drag.style.left=oEvent.clientX-this._x+px;this.Drag.style.top=oEvent.clientY-this._y+px;最后放开鼠标后就触发Stop程序结束拖放。这里的主要作用是把Start程序中给document添加的事件移除:removeEventHandler(document,mousemove,this._fM);removeEventHandler(document,mouseup,this._fS);这样一个简单的拖放程序就做好了,下面说说其他扩展和细节部分。【拖放锁定】锁定分三种,分别是:水平方向锁定(LockX)、垂直方向锁定(LockY)、完全锁定(Lock)。这个比较简单,水平和垂直方向的锁定只要在Move判断是否锁定再设置left和top就行,如果是完全锁定就直接返回。if(!this.LockX){this.Drag.style.left=;}if(!this.LockY){this.Drag.style.top=;}【触发对象】触发对象是用来触发拖放程序的,程序中通过Handle属性设置。有的时候不需要整个拖放对象都用来触发,这时就需要触发对象了。使用了触发对象后,进行移动的还是拖放对象,只是用触发对象来触发拖放(一般的使用是把触发对象放到拖放对象里面)。ps:触发对象的另一个用法是通过设置相同的Handle,实现一个触发对象同时拖放多个拖放对象。【范围限制】要设置范围限制必须先把Limit设为true。范围限制分两种,分别是固定范围和容器范围限制,主要在Move程序中设置。原理是当比较的值超过范围时,修正left和top要设置的值使拖放对象能保持在设置的范围内。【固定范围限制】容器范围限制就是指定上下左右的拖放范围。各个属性的意思是:上(mxTop):top限制;下(mxBottom):top+offsetHeight限制;左(mxLeft):left限制;右(mxRight):left+offsetWidth限制。如果范围设置不正确,可能导致上下或左右同时超过范围的情况,程序中有一个Repair程序用来修正范围参数的。Repair程序会在程序初始化和Start程序中执行,在Repair程序中修正mxRight和mxBottom:this.mxRight=Math.max(this.mxRight,this.mxLeft+this.Drag.offsetWidth);this.mxBottom=Math.max(this.mxBottom,this.mxTop+this.Drag.offsetHeight);其中mxLeft+offsetWidth和mxTop+offsetHeight分别是mxRight和mxBottom的最小范围值。根据范围参数修正移动参数:iLeft=Math.max(Math.min(iLeft,mxRight-this.Drag.offsetWidth),mxLeft);iTop=Math.max(Math.min(iTop,mxBottom-this.Drag.offsetHeight),mxTop);对于左边上边要取更大的值,对于右边下面就要取更小的值。【容器范围限制】容器范围限制的意思就是把范围限制在一个容器_mxContainer内。要注意的是拖放对象必须包含在_mxContainer中,因为程序中是使用相对定位来设置容器范围限制的(如果是在容器外就要用绝对定位,这样处理就比较麻烦了),还有就是容器空间要比拖放对象大,这个就不用说明了吧。原理跟固定范围限制差不多,只是范围参数是根据容器的属性的设置的。当设置了容器,在Repair程序会自动把position设为relative来相对定位:!this._mxContainer||CurrentStyle(this._mxContainer).position==relative||(this._mxContainer.style.position=relative);ps:其中CurrentStyle是用来获取最终样式(详细看这里的最终样式部分)。注意如果在程序执行之前设置过拖放对象的left和top而容器没有设置relative,在自动设置relative时会发生移位现象,所以程序在初始化时就执行一次Repair程序防止这种情况。因为offsetLeft和offsetTop要在设置relative之前获取才能正确获取值,所以在Start程序中Repair要在设置_x和_y之前执行。由于是相对定位,对于容器范围来说范围参数上下左右的值分别是0、clientHeight、0、clientWidth。clientWidth和clientHeight是容器可视部分的宽度和高度(详细参考这里)。为了容器范围能兼容固定范围的参数,程序中会获取容器范围和固定范围中范围更小的值:Code因为设置相对定位的关系,容器_mxContainer设置过后一般不要取消或修改,否则很容易造成移位异常。【鼠标捕获】我在一个拖放实例中看到,即使鼠标移动到浏览器外面,拖放程序依然能够执行,仔细查看后发现是用了setCapture。鼠标捕获(setCapture)是这个程序的重点,作用是将鼠标事件捕获到当前文档的指定的对象。这个对象会为当前应用程序或整个系统接收所有鼠标事件。使用很简单:this._Handle.setCapture();setCapture捕获以下鼠标事件:onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout。程序中主要是要捕获onmousemove和onmouseup事件。msdn的介绍中还说到setCapture有一个bool参数,用来设置在容器内的鼠标事件是否都被容器捕获。容器就是指调用setCapture的对象,大概意思就是:参数为true时(默认)容器会捕获容器内所有对象的鼠标事件,即容器内的对象不会触发鼠标事件(跟容器外的对象一样);参数为false时容器不会捕获容器内对象的鼠标事件,即容器内的对象可以正常地触发事件和取消冒泡。而对于容器外的鼠标事件无论参数是什么都会被捕获,可以用下面这个简单的例子测试一下(ie):Code这里的参数是true,一开始body会捕获所有鼠标事件,即使鼠标经过div也不会触发onmousemove事件。换成false的话,div就可以捕获鼠标事件,就能触发div的onmousemove事件了。拖放结束后还要使用releaseCapture释放鼠标,这个可以放在Stop程序中:this._Handle.releaseCapture();setCapture是ie的鼠标捕获方法,对于ff也有对应的captureEvents和releaseEvents方法。但这两个方法只能由window来调用,而且muxrwc说这两个方法在DOM2里已经废弃了,在ff里已经没用了。不过ff里貌似会自动设置取消鼠标捕获,但具体的情形就不清楚了,找不到一个比较详细的介绍,谁有这方面的资料记得告诉我啊。下面都是我的猜测,ff的鼠标捕获相当于能自动设置和释放的document.body.setCapture(false)。因为我测试下面的程序,发现ie和ff效果是差不多的:ie:Codeff:Code可惜没有权威的资料参考就只能猜猜了,还有很多还没有理解的地方以后再研究拉。注意ff2下的鼠标捕获有一个bug,当拖放对象内部没有文本内容并拖放到浏览器外时捕获就会失效。给拖放对象插入一个空文本,例如<fontsize='1px'>&nbsp;</font>就可以解决,不过这个bug在ff3已经修正了。【焦点丢失】一般情况下,鼠标捕获都能正常捕获事件,但如果浏览器窗口的焦点丢失就会导致捕获失效。我暂时测试到会导致焦点丢失的操作包括切换窗口(包括alt+tab),alert和popup等弹出窗体。当焦点丢失时应该同时执行Stop程序结束拖放,但当焦点丢失就不能捕获mouseup事件也就是不能触发_fS。还好ie有onlosecapture事件会在捕获失效时触发,针对这个情况可以这样设置:addEventHandler(this._Handle,losecapture,this._fS);并在Stop程序中移除:removeEventHandler(this._Handle,losecapture,this._fS);但ff没有类似的方法,不过muxrwc找到一个替代losecapture的window.onblur事件,那么可以在Start程序中设置:addEventHandler(window,blur,this._fS);在Stop程序中移除:removeEventHandler(window,blur,this._fS);那ie也有window.onblur事件,用window.onblur代替losecapture不就可以省一段代码了吗。接着我做了一些测试,发现基本上触发losecapture的情况都会同时触发window.onblur,看来真的可以。于是我修改程序用window.onblur代替losecapture,但测试后就出问题了,我发现如果我用alt+tab

1 / 19
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功