中文字幕日韩一区二区_国产一区二区av_国产毛片av_久久久久国产一区_色婷婷电影_国产一区二区精品

JavaScript 拖放效果代碼

這個(gè)程序的原型是在做圖片切割效果的時(shí)候做出來(lái)的,那時(shí)參考了好幾個(gè)同類的效果,跟muxrwc和BlueDestiny學(xué)習(xí)了不少東西。
雖然每次整理都覺(jué)得很好了,不過(guò)每隔一段時(shí)間又會(huì)發(fā)現(xiàn)得某個(gè)地方可以改善,某個(gè)地方有錯(cuò)誤,某些需求需要實(shí)現(xiàn),就像自己學(xué)習(xí)的知識(shí)那樣。
這里考慮到有的人可能只需要簡(jiǎn)單的拖放,所以有一個(gè)簡(jiǎn)化版的拖放SimpleDrag,方便學(xué)習(xí)。
效果預(yù)覽
ps:在maxthon下如果開(kāi)啟廣告過(guò)濾的話很可能會(huì)被過(guò)濾掉(不知有什么方法可以避免)。
程序說(shuō)明
【程序原理】
這里以SimpleDrag為例說(shuō)一下基本原理。
首先初始化程序中要一個(gè)拖放對(duì)象:
復(fù)制代碼 代碼如下:
this.Drag = $(drag);

還要兩個(gè)參數(shù)在開(kāi)始時(shí)記錄鼠標(biāo)相對(duì)拖放對(duì)象的坐標(biāo):
復(fù)制代碼 代碼如下:
this._x = this._y = 0;

還有兩個(gè)事件對(duì)象函數(shù)用于添加移除事件:
復(fù)制代碼 代碼如下:
this._fM = BindAsEventListener(this, this.Move);
this._fS = Bind(this, this.Stop);

分別是拖動(dòng)程序和停止拖動(dòng)程序。
拖放對(duì)象的position必須是absolute絕對(duì)定位:
復(fù)制代碼 代碼如下:
this.Drag.style.position = "absolute";

最后把Start開(kāi)始拖放程序綁定到拖放對(duì)象mousedown事件:
addEventHandler(this.Drag, "mousedown", BindAsEventListener(this, this.Start));
鼠標(biāo)在拖放對(duì)象按住,就會(huì)觸發(fā)Start程序,主要是用來(lái)準(zhǔn)備拖動(dòng),在這里記錄鼠標(biāo)相對(duì)拖放對(duì)象的坐標(biāo):
復(fù)制代碼 代碼如下:
this._x = oEvent.clientX - this.Drag.offsetLeft;
this._y = oEvent.clientY - this.Drag.offsetTop;

并把_fM拖動(dòng)程序和_fS停止拖動(dòng)程序分別綁定到document的mousemove和mouseup事件:
復(fù)制代碼 代碼如下:
addEventHandler(document, "mousemove", this._fM);
addEventHandler(document, "mouseup", this._fS);

注意要綁定到document才可以保證事件在整個(gè)窗口文檔中都有效,如果只綁定到拖放對(duì)象就很容易出現(xiàn)拖太快就脫節(jié)的現(xiàn)象。
當(dāng)鼠標(biāo)在文檔上移動(dòng)時(shí),就會(huì)觸發(fā)Move程序了,這里就是實(shí)現(xiàn)拖動(dòng)的程序。
通過(guò)現(xiàn)在鼠標(biāo)的坐標(biāo)值跟開(kāi)始拖動(dòng)時(shí)鼠標(biāo)相對(duì)的坐標(biāo)值的差就可以得到拖放對(duì)象應(yīng)該設(shè)置的left和top了:
this.Drag.style.left = oEvent.clientX - this._x + "px";
this.Drag.style.top = oEvent.clientY - this._y + "px";
最后放開(kāi)鼠標(biāo)后就觸發(fā)Stop程序結(jié)束拖放。
這里的主要作用是把Start程序中給document添加的事件移除:
removeEventHandler(document, "mousemove", this._fM);
removeEventHandler(document, "mouseup", this._fS);
這樣一個(gè)簡(jiǎn)單的拖放程序就做好了,下面說(shuō)說(shuō)其他擴(kuò)展和細(xì)節(jié)部分。
【拖放鎖定】
鎖定分三種,分別是:水平方向鎖定(LockX)、垂直方向鎖定(LockY)、完全鎖定(Lock)。
這個(gè)比較簡(jiǎn)單,水平和垂直方向的鎖定只要在Move判斷是否鎖定再設(shè)置left和top就行,如果是完全鎖定就直接返回。
if(!this.LockX){ this.Drag.style.left = ; }
if(!this.LockY){ this.Drag.style.top = ; }
【觸發(fā)對(duì)象】
觸發(fā)對(duì)象是用來(lái)觸發(fā)拖放程序的,程序中通過(guò)Handle屬性設(shè)置。有的時(shí)候不需要整個(gè)拖放對(duì)象都用來(lái)觸發(fā),這時(shí)就需要觸發(fā)對(duì)象了。
使用了觸發(fā)對(duì)象后,進(jìn)行移動(dòng)的還是拖放對(duì)象,只是用觸發(fā)對(duì)象來(lái)觸發(fā)拖放(一般的使用是把觸發(fā)對(duì)象放到拖放對(duì)象里面)。
ps:觸發(fā)對(duì)象的另一個(gè)用法是通過(guò)設(shè)置相同的Handle,實(shí)現(xiàn)一個(gè)觸發(fā)對(duì)象同時(shí)拖放多個(gè)拖放對(duì)象。
【范圍限制】
要設(shè)置范圍限制必須先把Limit設(shè)為true。范圍限制分兩種,分別是固定范圍和容器范圍限制,主要在Move程序中設(shè)置。
原理是當(dāng)比較的值超過(guò)范圍時(shí),修正left和top要設(shè)置的值使拖放對(duì)象能保持在設(shè)置的范圍內(nèi)。
【固定范圍限制】
容器范圍限制就是指定上下左右的拖放范圍。
各個(gè)屬性的意思是:
上(mxTop):top限制;
下(mxBottom):top+offsetHeight限制;
左(mxLeft):left限制;
右(mxRight):left+offsetWidth限制。
如果范圍設(shè)置不正確,可能導(dǎo)致上下或左右同時(shí)超過(guò)范圍的情況,程序中有一個(gè)Repair程序用來(lái)修正范圍參數(shù)的。
Repair程序會(huì)在程序初始化和Start程序中執(zhí)行,在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的最小范圍值。
根據(jù)范圍參數(shù)修正移動(dòng)參數(shù):
iLeft = Math.max(Math.min(iLeft, mxRight - this.Drag.offsetWidth), mxLeft);
iTop = Math.max(Math.min(iTop, mxBottom - this.Drag.offsetHeight), mxTop);
對(duì)于左邊上邊要取更大的值,對(duì)于右邊下面就要取更小的值。
【容器范圍限制】
容器范圍限制的意思就是把范圍限制在一個(gè)容器_mxContainer內(nèi)。
要注意的是拖放對(duì)象必須包含在_mxContainer中,因?yàn)槌绦蛑惺鞘褂孟鄬?duì)定位來(lái)設(shè)置容器范圍限制的(如果是在容器外就要用絕對(duì)定位,這樣處理就比較麻煩了),還有就是容器空間要比拖放對(duì)象大,這個(gè)就不用說(shuō)明了吧。
原理跟固定范圍限制差不多,只是范圍參數(shù)是根據(jù)容器的屬性的設(shè)置的。
當(dāng)設(shè)置了容器,在Repair程序會(huì)自動(dòng)把position設(shè)為relative來(lái)相對(duì)定位:
!this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer.style.position = "relative");
ps:其中CurrentStyle是用來(lái)獲取最終樣式(詳細(xì)看這里的最終樣式部分)。
注意如果在程序執(zhí)行之前設(shè)置過(guò)拖放對(duì)象的left和top而容器沒(méi)有設(shè)置relative,在自動(dòng)設(shè)置relative時(shí)會(huì)發(fā)生移位現(xiàn)象,所以程序在初始化時(shí)就執(zhí)行一次Repair程序防止這種情況。因?yàn)閛ffsetLeft和offsetTop要在設(shè)置relative之前獲取才能正確獲取值,所以在Start程序中Repair要在設(shè)置_x和_y之前執(zhí)行。
由于是相對(duì)定位,對(duì)于容器范圍來(lái)說(shuō)范圍參數(shù)上下左右的值分別是0、clientHeight、0、clientWidth。
clientWidth和clientHeight是容器可視部分的寬度和高度(詳細(xì)參考這里)。
為了容器范圍能兼容固定范圍的參數(shù),程序中會(huì)獲取容器范圍和固定范圍中范圍更小的值:
Code
mxLeft = Math.max(mxLeft, 0);
mxTop = Math.max(mxTop, 0);
mxRight = Math.min(mxRight, this._mxContainer.clientWidth);
mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight);
因?yàn)樵O(shè)置相對(duì)定位的關(guān)系,容器_mxContainer設(shè)置過(guò)后一般不要取消或修改,否則很容易造成移位異常。
【鼠標(biāo)捕獲】
我在一個(gè)拖放實(shí)例中看到,即使鼠標(biāo)移動(dòng)到瀏覽器外面,拖放程序依然能夠執(zhí)行,仔細(xì)查看后發(fā)現(xiàn)是用了setCapture。
鼠標(biāo)捕獲(setCapture)是這個(gè)程序的重點(diǎn),作用是將鼠標(biāo)事件捕獲到當(dāng)前文檔的指定的對(duì)象。這個(gè)對(duì)象會(huì)為當(dāng)前應(yīng)用程序或整個(gè)系統(tǒng)接收所有鼠標(biāo)事件。
使用很簡(jiǎn)單:
this._Handle.setCapture();
setCapture捕獲以下鼠標(biāo)事件:onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout。
程序中主要是要捕獲onmousemove和onmouseup事件。
msdn的介紹中還說(shuō)到setCapture有一個(gè)bool參數(shù),用來(lái)設(shè)置在容器內(nèi)的鼠標(biāo)事件是否都被容器捕獲。
容器就是指調(diào)用setCapture的對(duì)象,大概意思就是:
參數(shù)為true時(shí)(默認(rèn))容器會(huì)捕獲容器內(nèi)所有對(duì)象的鼠標(biāo)事件,即容器內(nèi)的對(duì)象不會(huì)觸發(fā)鼠標(biāo)事件(跟容器外的對(duì)象一樣);
參數(shù)為false時(shí)容器不會(huì)捕獲容器內(nèi)對(duì)象的鼠標(biāo)事件,即容器內(nèi)的對(duì)象可以正常地觸發(fā)事件和取消冒泡。
而對(duì)于容器外的鼠標(biāo)事件無(wú)論參數(shù)是什么都會(huì)被捕獲,可以用下面這個(gè)簡(jiǎn)單的例子測(cè)試一下(ie):
Code
<html>
<body onclick="alert(2)">
<div onmousemove="alert(1)">mouseover</div>
<script>document.body.setCapture();</script>
</body>
</html>
這里的參數(shù)是true,一開(kāi)始body會(huì)捕獲所有鼠標(biāo)事件,即使鼠標(biāo)經(jīng)過(guò)div也不會(huì)觸發(fā)onmousemove事件。
換成false的話,div就可以捕獲鼠標(biāo)事件,就能觸發(fā)div的onmousemove事件了。
拖放結(jié)束后還要使用releaseCapture釋放鼠標(biāo),這個(gè)可以放在Stop程序中:
this._Handle.releaseCapture();
setCapture是ie的鼠標(biāo)捕獲方法,對(duì)于ff也有對(duì)應(yīng)的captureEvents和releaseEvents方法。
但這兩個(gè)方法只能由window來(lái)調(diào)用,而且muxrwc說(shuō)這兩個(gè)方法在DOM2里已經(jīng)廢棄了,在ff里已經(jīng)沒(méi)用了。
不過(guò)ff里貌似會(huì)自動(dòng)設(shè)置取消鼠標(biāo)捕獲,但具體的情形就不清楚了,找不到一個(gè)比較詳細(xì)的介紹,誰(shuí)有這方面的資料記得告訴我啊。
下面都是我的猜測(cè),ff的鼠標(biāo)捕獲相當(dāng)于能自動(dòng)設(shè)置和釋放的document.body.setCapture(false)。
因?yàn)槲覝y(cè)試下面的程序,發(fā)現(xiàn)ie和ff效果是差不多的:
ie:
Code
<html>
<body>
<div id="aa" onmouseover="alert(1)"></div>
<script>
document.body.onmousedown=function(){this.setCapture(false)}
document.body.onmouseup=function(){this.releaseCapture()}
document.onmousemove=function(){aa.innerHTML+=1}
</script>
</body>
</html>
ff:
Code
<html>
<body>
<div id="aa" onmouseover="alert(1)"></div>
<script>
document.onmousemove=function(){aa.innerHTML+=1}
</script>
</body>
</html>
可惜沒(méi)有權(quán)威的資料參考就只能猜猜了,還有很多還沒(méi)有理解的地方以后再研究拉。
注意ff2下的鼠標(biāo)捕獲有一個(gè)bug,當(dāng)拖放對(duì)象內(nèi)部沒(méi)有文本內(nèi)容并拖放到瀏覽器外時(shí)捕獲就會(huì)失效。
給拖放對(duì)象插入一個(gè)空文本,例如<font size='1px'> </font>就可以解決,不過(guò)這個(gè)bug在ff3已經(jīng)修正了。
【焦點(diǎn)丟失】
一般情況下,鼠標(biāo)捕獲都能正常捕獲事件,但如果瀏覽器窗口的焦點(diǎn)丟失就會(huì)導(dǎo)致捕獲失效。
我暫時(shí)測(cè)試到會(huì)導(dǎo)致焦點(diǎn)丟失的操作包括切換窗口(包括alt+tab),alert和popup等彈出窗體。
當(dāng)焦點(diǎn)丟失時(shí)應(yīng)該同時(shí)執(zhí)行Stop程序結(jié)束拖放,但當(dāng)焦點(diǎn)丟失就不能捕獲mouseup事件也就是不能觸發(fā)_fS。
還好ie有onlosecapture事件會(huì)在捕獲失效時(shí)觸發(fā),針對(duì)這個(gè)情況可以這樣設(shè)置:
addEventHandler(this._Handle, "losecapture", this._fS);
并在Stop程序中移除:
removeEventHandler(this._Handle, "losecapture", this._fS);
但ff沒(méi)有類似的方法,不過(guò)muxrwc找到一個(gè)替代losecapture的window.onblur事件,那么可以在Start程序中設(shè)置:
addEventHandler(window, "blur", this._fS);
在Stop程序中移除:
removeEventHandler(window, "blur", this._fS);
那ie也有window.onblur事件,用window.onblur代替losecapture不就可以省一段代碼了嗎。
接著我做了一些測(cè)試,發(fā)現(xiàn)基本上觸發(fā)losecapture的情況都會(huì)同時(shí)觸發(fā)window.onblur,看來(lái)真的可以。
于是我修改程序用window.onblur代替losecapture,但測(cè)試后就出問(wèn)題了,我發(fā)現(xiàn)如果我用alt+tab切換到另一個(gè)窗口,拖動(dòng)還可以繼續(xù),但這個(gè)時(shí)候應(yīng)該是已經(jīng)丟失焦點(diǎn)了。
于是我逐一排除測(cè)試和程序代碼,結(jié)果發(fā)現(xiàn)如果使用了DTD,那么window.onblur會(huì)在再次獲得焦點(diǎn)時(shí)才會(huì)觸發(fā)。
大家可以用下面這段代碼測(cè)試:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script>window.onblur=function(){alert(1)}</script>
在切換到其他程序后,再切換回來(lái)才會(huì)觸發(fā)window.onblur,還有幾個(gè)比較怪異的狀況就不說(shuō)了,反正ie用window.onblur是不理想的了。
【取消默認(rèn)動(dòng)作】
對(duì)選擇狀態(tài)的文本內(nèi)容、連接和圖片等進(jìn)行拖放操作會(huì)觸發(fā)系統(tǒng)的默認(rèn)動(dòng)作,例如ie中拖動(dòng)圖片鼠標(biāo)會(huì)變成禁止操作狀態(tài),這樣會(huì)導(dǎo)致這個(gè)拖放程序執(zhí)行失敗。
不過(guò)ie在設(shè)置了setCapture之后,通過(guò)用戶界面用鼠標(biāo)進(jìn)行拖放操作和內(nèi)容選擇都會(huì)被禁止。
意思就是setCapture之后就不能對(duì)文檔內(nèi)容進(jìn)行拖放和選擇,注意這里的拖放是指系統(tǒng)的默認(rèn)動(dòng)作,例如ondragstart就不會(huì)被觸發(fā)。
不過(guò)如果setCapture的參數(shù)是false的話,容器內(nèi)的對(duì)象還是可以觸發(fā)事件的(具體看鼠標(biāo)捕獲部分),所以setCapture的參數(shù)要設(shè)成true或保留默認(rèn)值。
而ff的鼠標(biāo)捕獲沒(méi)有這個(gè)功能,但可以用preventDefault來(lái)取消事件的默認(rèn)動(dòng)作來(lái)解決:
oEvent.preventDefault();
ps:據(jù)說(shuō)使用preventDefault會(huì)出現(xiàn)mouseup丟失的情況,但我在ff3中測(cè)試沒(méi)有發(fā)現(xiàn),如果各位發(fā)現(xiàn)任何mouseup丟失的情況,務(wù)必告訴我啊。
【清除選擇】
ie在設(shè)置setCapture之后內(nèi)容選擇都會(huì)被禁止,但也因此不會(huì)清除在設(shè)置之前就已經(jīng)選擇的內(nèi)容,而且設(shè)置之后也能通過(guò)其他方式選擇內(nèi)容,
例如用ctrl+a來(lái)選擇內(nèi)容。
ps:onkeydown、onkeyup和onkeypress事件不會(huì)受到鼠標(biāo)捕獲影響。
而ff在mousedown時(shí)就能清除原來(lái)選擇的內(nèi)容,但拖動(dòng)鼠標(biāo),ctrl+a時(shí)還是會(huì)繼續(xù)選擇內(nèi)容。
不過(guò)在取消了系統(tǒng)默認(rèn)動(dòng)作之后,這樣的選擇并不會(huì)對(duì)拖放操作造成影響,這里設(shè)置主要還是為了更好的體驗(yàn)。
以前我用禁止拖放對(duì)象被選擇的方法來(lái)達(dá)到目的,即ie中設(shè)置拖放對(duì)象的onselectstart返回false,在ff中設(shè)置樣式MozUserSelect(css:-moz-user-select)為none。
但這種方法只能禁止拖放對(duì)象本身被選擇,后來(lái)找到個(gè)更好的方法清除選擇,不但不影響拖放對(duì)象的選擇效果,還能對(duì)整個(gè)文檔進(jìn)行清除:
ie:document.selection.empty()
ff:window.getSelection().removeAllRanges()
為了防止在拖放過(guò)程中選擇內(nèi)容,所以把它放到Move程序中,下面是兼容的寫法:
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
【margin】
還有一個(gè)情況,當(dāng)拖放對(duì)象設(shè)置了margin,那么拖放的時(shí)候就會(huì)錯(cuò)位(給SimpleDrag的拖放對(duì)象設(shè)置margin就可以測(cè)試)。
原因是在Start程序設(shè)置_x和_y時(shí)是使用offset獲取的,而這個(gè)值是包括margin的,所以在設(shè)置left和top之前要減去這個(gè)margin。
但如果在Start程序中就去掉margin那么在Move程序中設(shè)置范圍限制時(shí)就會(huì)計(jì)算錯(cuò)誤,
所以最好是在Start程序中獲取值:
this._marginLeft = parseInt(CurrentStyle(this.Drag).marginLeft) || 0;
this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0;
在Move程序中設(shè)置值:
this.Drag.style.left = iLeft - this._marginLeft + "px";
this.Drag.style.top = iTop - this._marginTop + "px";
要注意margin要在范圍修正之后再設(shè)置,否則會(huì)錯(cuò)位。
【透明背景bug】
在ie有一個(gè)透明背景bug(不知算不算bug),可以用下面的代碼測(cè)試:
Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<div onmousedown="alert(1)" style="border:10px solid #C4E3FD; width:50px; height:50px;position:absolute;"></div>
</body>
</html>
點(diǎn)擊div的背景會(huì)觸發(fā)不了事件(點(diǎn)擊邊框或div里面的對(duì)象是可以觸發(fā)的)。
到底什么時(shí)候會(huì)出現(xiàn)這個(gè)bug呢,再用下面的代碼測(cè)試:
Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html style="background-color:#fff;">
<style>div{height:100px; border:10px solid #000;}</style>
<body style="border:10px solid #FF0000;background-color:#ccc;">
<div style="position:relative;width:150px;">
<div style="border-color:#3F3;width:30px; height:150px;background-color:#ccc; position:absolute;left:0"></div>
<img style="width:40px; height:170px; position:absolute;left:50px" src="1.jpg" temp_src="1.jpg" />
<div onclick="alert(1)" style="border-color:#00F;position:absolute;top:50px; width:200px; left:0"></div>
</div>
</body>
</html>
測(cè)試代碼中我把背景顏色(包括body)設(shè)成灰色,首先可以看出在藍(lán)色div(測(cè)試對(duì)象)內(nèi)只要觸發(fā)點(diǎn)是在灰色上面,就能觸發(fā)事件;相反,在其他不是背景的地方,即使是邊框、圖片,也不能觸發(fā)事件。
就像是把灰色的背景的補(bǔ)到藍(lán)色div上來(lái),而且僅僅是背景能這樣,多奇怪的設(shè)定啊。
這里要說(shuō)明的是body比較特別,不管背景是不是透明,只要觸發(fā)點(diǎn)是直接在body上就能觸發(fā)事件。
我的結(jié)論是如果觸發(fā)事件的對(duì)象背景是透明的,而事件的觸發(fā)點(diǎn)不在對(duì)象內(nèi)的元素上,也不是直接在body上,而且透明背景外沒(méi)有非透明背景的話,那么事件觸發(fā)就會(huì)失敗。
這個(gè)結(jié)論寫得不太好,因?yàn)槲叶疾恢脑趺幢磉_(dá)這奇怪的設(shè)定,希望各位能明白。
ps:這里設(shè)置圖片背景跟顏色背景效果是一樣的。
那最好解決的方法就是給對(duì)象設(shè)一個(gè)非透明背景,但有時(shí)需求正好是要透明的,那怎么辦呢?
首先想到的是加上背景色后設(shè)置完全透明,但這樣連邊框,容器內(nèi)的對(duì)象等都完全透明了,不夠好。
如果能保證觸發(fā)點(diǎn)直接在body或非背景上也可以,如果這個(gè)也不能保證呢?
我想到的一個(gè)解決方法是在容器里面加一個(gè)層,覆蓋整個(gè)容器,并設(shè)置背景色和完全透明:
Code
with(this._Handle.appendChild(document.createElement("div")).style){
width = height = "100%"; backgroundColor = "#fff"; filter = "alpha(opacity:0)";
}
到這里又不得不說(shuō)ie6的一個(gè)渲染bug,用下面的代碼測(cè)試(ie6):
Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<div id="aa" style="width:300px;height:100px;border:1px solid;"><div style="background:#00f;height:100%;"></div></div>
<script>setTimeout("aa.style.height=200",0)</script>
</body>
</html>
可以對(duì)比ie7的效果,可以看出里面的div雖然高度設(shè)置了100%,但在外面的div修改高度之后,卻不知什么原因沒(méi)有填充了。
如果這個(gè)div是拖動(dòng)對(duì)象,突然有一半拖不動(dòng)了,那肯定不行。
還好BlueDestiny告訴我一個(gè)解決方法,設(shè)置對(duì)象的overflow為hidden,里面的div又會(huì)自動(dòng)填充了。
BlueDestiny說(shuō)“出現(xiàn)這個(gè)問(wèn)題的原因是因?yàn)镮E6渲染的問(wèn)題,通過(guò)某些CSS的屬性可以讓DOM改變之后再次渲染。”
這個(gè)bug也有用zoom解決的,反正就是要使dom再次渲染。
當(dāng)發(fā)現(xiàn)程序有這個(gè)bug出現(xiàn),把程序可選參數(shù)Transparent設(shè)為true就會(huì)自動(dòng)插入這樣一個(gè)層了。
到這里插入一個(gè)小知識(shí)吧,細(xì)心的話會(huì)發(fā)現(xiàn)上面的測(cè)試代碼中我給html設(shè)了一個(gè)背景色。
大家可以去掉這個(gè)背景色,會(huì)發(fā)現(xiàn)背景色會(huì)設(shè)置到整個(gè)頁(yè)面,雖然一直都是用body設(shè)置頁(yè)面背景色,但現(xiàn)在會(huì)不會(huì)有一個(gè)疑惑,body是紅色框的部分,為什么設(shè)置它的背景色就能應(yīng)用到整個(gè)頁(yè)面,而給html設(shè)置了背景色就又“正常”顯示了呢。
這個(gè)可以從CSS21的w3c標(biāo)準(zhǔn)中關(guān)于background的部分看到原因:
For HTML documents, however, we recommend that authors specify the background for the BODY element rather than the HTML element. For HTML documents whose root HTML element has computed values of 'transparent' for 'background-color' and 'none' for 'background-image', user agents must instead use the computed value of those properties from that HTML element's first BODY element child when painting backgrounds for the canvas, and must not paint a background for that BODY element. Such backgrounds must also be anchored at the same point as they would be if they were painted only for the root element. This does not apply to XHTML documents.
我英文很爛,就勉強(qiáng)翻譯一下吧:
對(duì)于HTML文檔,我們建議作者(這是對(duì)瀏覽器的制作者說(shuō)的)使用BODY元素的background,而不是HTML元素的。如果HTML文檔的根元素(HTML元素)的'background-color'是'transparent',同時(shí)'background-image'是'none'(這兩個(gè)剛好就是默認(rèn)值),那么在設(shè)置背景時(shí)就取HTML元素的第一個(gè)BODY子元素的屬性值,并且不再渲染那個(gè)元素的background。
后面兩個(gè)句就看不太懂了,不過(guò)已經(jīng)足夠解析原因了。
【iframe】
如果頁(yè)面上有嵌入iframe,那就要注意了,因?yàn)槭髽?biāo)捕獲在iframe上會(huì)有問(wèn)題。
例如在拖放容器內(nèi)的一個(gè)iframe上快速移動(dòng)拖放,或者鼠標(biāo)拖動(dòng)到容器外的一個(gè)iframe上,反正就是鼠標(biāo)在iframe上(注意沒(méi)有其他元素隔開(kāi)),就會(huì)出問(wèn)題:
首先是捕獲的失效,鼠標(biāo)在iframe上,就拖不動(dòng)了,但并不會(huì)觸發(fā)losecapture,更不用說(shuō)window的blur了,這個(gè)在ie和ff都是一樣;
其次ie里在iframe多摩擦幾次,還可能導(dǎo)致ie死掉(原因不明)。
下面是我想到的幾種方法:
隱藏頁(yè)面的iframe,比較簡(jiǎn)單,但可能有些在iframe中重要的信息也被隱藏,或者造成頁(yè)面布局的錯(cuò)位,用戶體驗(yàn)不好;
鼠標(biāo)移動(dòng)到iframe后取消拖放,難度不大,但同樣用戶體驗(yàn)不好;
每個(gè)iframe用一個(gè)透明的層遮住,很麻煩,要計(jì)算好每個(gè)iframe的位置和大小;
用一個(gè)透明的層把整個(gè)頁(yè)面遮住,比較推薦,也比較簡(jiǎn)單,下面介紹這種做法。
我在仿LightBox內(nèi)容顯示效果做的那個(gè)覆蓋層正好能應(yīng)用在這里,首先實(shí)例化一個(gè)透明的覆蓋層:
var ol = new OverLay({ Opacity: 0 });
然后在onStart和onStop事件中添加ol.Show()和ol.Close()來(lái)顯示和隱藏覆蓋層就可以了,這樣只要不是在iframe觸發(fā)拖放就沒(méi)有問(wèn)題了。
有其他更好的方法也請(qǐng)各位指教。
暫時(shí)就研究到這里,想不到小小的拖放就有這么多的學(xué)問(wèn)。
還有滾屏等這些都還沒(méi)考慮到呢,等以后有需要了再來(lái)研究拉。

使用說(shuō)明
實(shí)例化時(shí)只需要一個(gè)參數(shù),就是拖放對(duì)象:
new SimpleDrag("idDrag");
有以下這些可選參數(shù)和屬性:
屬性:默認(rèn)值//說(shuō)明
Handle:"",//設(shè)置觸發(fā)對(duì)象(不設(shè)置則使用拖放對(duì)象)
Limit:false,//是否設(shè)置范圍限制(為true時(shí)下面參數(shù)有用,可以是負(fù)數(shù))
mxLeft:0,//左邊限制
mxRight:9999,//右邊限制
mxTop:0,//上邊限制
mxBottom:9999,//下邊限制
mxContainer:"",//指定限制在容器內(nèi)
LockX:false,//是否鎖定水平方向拖放
LockY:false,//是否鎖定垂直方向拖放
Lock:false,//是否鎖定
Transparent: false,//是否透明
onStart:function(){},//開(kāi)始移動(dòng)時(shí)執(zhí)行
onMove:function(){},//移動(dòng)時(shí)執(zhí)行
onStop:function(){}//結(jié)束移動(dòng)時(shí)執(zhí)行
還有屬性Drag是拖放對(duì)象,Transparent、Handle和mxContainer初始化后就不能再設(shè)置。

程序代碼
Code 
復(fù)制代碼 代碼如下:
var isIE = (document.all) ? true : false;
var $ = function (id) {
return "string" == typeof id ? document.getElementById(id) : id;
};
var Class = {
create: function() {
return function() { this.initialize.apply(this, arguments); }
}
}
var Extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
}
var Bind = function(object, fun) {
return function() {
return fun.apply(object, arguments);
}
}
var BindAsEventListener = function(object, fun) {
return function(event) {
return fun.call(object, (event || window.event));
}
}
var CurrentStyle = function(element){
return element.currentStyle || document.defaultView.getComputedStyle(element, null);
}
function addEventHandler(oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
} else if (oTarget.attachEvent) {
oTarget.attachEvent("on" + sEventType, fnHandler);
} else {
oTarget["on" + sEventType] = fnHandler;
}
};
function removeEventHandler(oTarget, sEventType, fnHandler) {
if (oTarget.removeEventListener) {
oTarget.removeEventListener(sEventType, fnHandler, false);
} else if (oTarget.detachEvent) {
oTarget.detachEvent("on" + sEventType, fnHandler);
} else {
oTarget["on" + sEventType] = null;
}
};
//拖放程序
var Drag = Class.create();
Drag.prototype = {
//拖放對(duì)象
initialize: function(drag, options) {
this.Drag = $(drag);//拖放對(duì)象
this._x = this._y = 0;//記錄鼠標(biāo)相對(duì)拖放對(duì)象的位置
this._marginLeft = this._marginTop = 0;//記錄margin
//事件對(duì)象(用于綁定移除事件)
this._fM = BindAsEventListener(this, this.Move);
this._fS = Bind(this, this.Stop);
this.SetOptions(options);
this.Limit = !!this.options.Limit;
this.mxLeft = parseInt(this.options.mxLeft);
this.mxRight = parseInt(this.options.mxRight);
this.mxTop = parseInt(this.options.mxTop);
this.mxBottom = parseInt(this.options.mxBottom);
this.LockX = !!this.options.LockX;
this.LockY = !!this.options.LockY;
this.Lock = !!this.options.Lock;
this.onStart = this.options.onStart;
this.onMove = this.options.onMove;
this.onStop = this.options.onStop;
this._Handle = $(this.options.Handle) || this.Drag;
this._mxContainer = $(this.options.mxContainer) || null;
this.Drag.style.position = "absolute";
//透明
if(isIE && !!this.options.Transparent){
//填充拖放對(duì)象
with(this._Handle.appendChild(document.createElement("div")).style){
width = height = "100%"; backgroundColor = "#fff"; filter = "alpha(opacity:0)";
}
}
//修正范圍
this.Repair();
addEventHandler(this._Handle, "mousedown", BindAsEventListener(this, this.Start));
},
//設(shè)置默認(rèn)屬性
SetOptions: function(options) {
this.options = {//默認(rèn)值
Handle: "",//設(shè)置觸發(fā)對(duì)象(不設(shè)置則使用拖放對(duì)象)
Limit: false,//是否設(shè)置范圍限制(為true時(shí)下面參數(shù)有用,可以是負(fù)數(shù))
mxLeft: 0,//左邊限制
mxRight: 9999,//右邊限制
mxTop: 0,//上邊限制
mxBottom: 9999,//下邊限制
mxContainer: "",//指定限制在容器內(nèi)
LockX: false,//是否鎖定水平方向拖放
LockY: false,//是否鎖定垂直方向拖放
Lock: false,//是否鎖定
Transparent: false,//是否透明
onStart: function(){},//開(kāi)始移動(dòng)時(shí)執(zhí)行
onMove: function(){},//移動(dòng)時(shí)執(zhí)行
onStop: function(){}//結(jié)束移動(dòng)時(shí)執(zhí)行
};
Extend(this.options, options || {});
},
//準(zhǔn)備拖動(dòng)
Start: function(oEvent) {
if(this.Lock){ return; }
this.Repair();
//記錄鼠標(biāo)相對(duì)拖放對(duì)象的位置
this._x = oEvent.clientX - this.Drag.offsetLeft;
this._y = oEvent.clientY - this.Drag.offsetTop;
//記錄margin
this._marginLeft = parseInt(CurrentStyle(this.Drag).marginLeft) || 0;
this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0;
//mousemove時(shí)移動(dòng) mouseup時(shí)停止
addEventHandler(document, "mousemove", this._fM);
addEventHandler(document, "mouseup", this._fS);
if(isIE){
//焦點(diǎn)丟失
addEventHandler(this._Handle, "losecapture", this._fS);
//設(shè)置鼠標(biāo)捕獲
this._Handle.setCapture();
}else{
//焦點(diǎn)丟失
addEventHandler(window, "blur", this._fS);
//阻止默認(rèn)動(dòng)作
oEvent.preventDefault();
};
//附加程序
this.onStart();
},
//修正范圍
Repair: function() {
if(this.Limit){
//修正錯(cuò)誤范圍參數(shù)
this.mxRight = Math.max(this.mxRight, this.mxLeft + this.Drag.offsetWidth);
this.mxBottom = Math.max(this.mxBottom, this.mxTop + this.Drag.offsetHeight);
//如果有容器必須設(shè)置position為relative來(lái)相對(duì)定位,并在獲取offset之前設(shè)置
!this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer.style.position = "relative");
}
},
//拖動(dòng)
Move: function(oEvent) {
//判斷是否鎖定
if(this.Lock){ this.Stop(); return; };
//清除選擇
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
//設(shè)置移動(dòng)參數(shù)
var iLeft = oEvent.clientX - this._x, iTop = oEvent.clientY - this._y;
//設(shè)置范圍限制
if(this.Limit){
//設(shè)置范圍參數(shù)
var mxLeft = this.mxLeft, mxRight = this.mxRight, mxTop = this.mxTop, mxBottom = this.mxBottom;
//如果設(shè)置了容器,再修正范圍參數(shù)
if(!!this._mxContainer){
mxLeft = Math.max(mxLeft, 0);
mxTop = Math.max(mxTop, 0);
mxRight = Math.min(mxRight, this._mxContainer.clientWidth);
mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight);
};
//修正移動(dòng)參數(shù)
iLeft = Math.max(Math.min(iLeft, mxRight - this.Drag.offsetWidth), mxLeft);
iTop = Math.max(Math.min(iTop, mxBottom - this.Drag.offsetHeight), mxTop);
}
//設(shè)置位置,并修正margin
if(!this.LockX){ this.Drag.style.left = iLeft - this._marginLeft + "px"; }
if(!this.LockY){ this.Drag.style.top = iTop - this._marginTop + "px"; }
//附加程序
this.onMove();
},
//停止拖動(dòng)
Stop: function() {
//移除事件
removeEventHandler(document, "mousemove", this._fM);
removeEventHandler(document, "mouseup", this._fS);
if(isIE){
removeEventHandler(this._Handle, "losecapture", this._fS);
this._Handle.releaseCapture();
}else{
removeEventHandler(window, "blur", this._fS);
};
//附加程序
this.onStop();
}
};

測(cè)試代碼:
Code
復(fù)制代碼 代碼如下:
<style>
#idContainer{ border:10px solid #990000; width:600px; height:300px;}
#idDrag{ border:5px solid #C4E3FD; background:#C4E3FD; width:50px; height:50px; top:50px; left:50px;}
#idHandle{cursor:move; height:25px; background:#0000FF; overflow:hidden;}
</style>
<div id="idContainer">
<div id="idDrag"><div id="idHandle"></div></div>
</div>
<input id="idReset" type="button" value="復(fù)位" />
<input id="idLock" type="button" value="鎖定" />
<input id="idLockX" type="button" value="鎖定水平" />
<input id="idLockY" type="button" value="鎖定垂直" />
<input id="idLimit" type="button" value="范圍鎖定" />
<input id="idLimitOff" type="button" value="取消范圍鎖定" />
<br />拖放狀態(tài):<span id="idShow">未開(kāi)始</span>
<script>
var drag = new Drag("idDrag", { mxContainer: "idContainer", Handle: "idHandle", Limit: true,
onStart: function(){ $("idShow").innerHTML = "開(kāi)始拖放"; },
onMove: function(){ $("idShow").innerHTML = "left:"+this.Drag.offsetLeft+";top:"+this.Drag.offsetTop; },
onStop: function(){ $("idShow").innerHTML = "結(jié)束拖放"; }
});
$("idReset").onclick = function(){
drag.Limit = true;
drag.mxLeft = drag.mxTop = 0;
drag.mxRight = drag.mxBottom = 9999;
drag.LockX = drag.LockY = drag.Lock = false;
}
$("idLock").onclick = function(){ drag.Lock = true; }
$("idLockX").onclick = function(){ drag.LockX = true; }
$("idLockY").onclick = function(){ drag.LockY = true; }
$("idLimit").onclick = function(){ drag.mxRight = drag.mxBottom = 200;drag.Limit = true; }
$("idLimitOff").onclick = function(){ drag.Limit = false; }
</script>


[Ctrl+A 全選 注:如需引入外部Js需刷新才能執(zhí)行]

JavaScript技術(shù)JavaScript 拖放效果代碼,轉(zhuǎn)載需保留來(lái)源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 草草草影院 | 日本免费小视频 | 国产色在线 | 欧美4p| 欧美一二区 | 久久久精品影院 | 国产原创在线观看 | 伊人导航| 国产一区亚洲二区三区 | 国产一区二区三区免费观看视频 | 国产女人与拘做受视频 | 亚洲精品久久久久中文字幕欢迎你 | 国产精品美女久久久久久免费 | 亚洲男人天堂av | 亚洲欧洲在线观看视频 | 国产一区久久久 | 欧美在线a | 国产农村妇女毛片精品久久麻豆 | 免费视频二区 | 日韩精品一二三 | 妖精视频一区二区三区 | 日日夜夜天天 | 视频一区在线观看 | 在线观看精品视频网站 | 久久精品亚洲成在人线av网址 | 国产1区2区| 女人精96xxx免费网站p | 米奇7777狠狠狠狠视频 | 欧美日韩国产一区二区三区 | 九九看片 | 欧美精品一区二区三区四区 在线 | 欧美激情在线一区二区三区 | 精品1区2区 | 亚洲福利一区二区 | 国产一级在线 | 亚洲精品国产综合区久久久久久久 | 成人不卡视频 | 亚洲国产一区视频 | 日韩在线欧美 | 亚洲精品一区二区三区四区高清 | 日韩精品视频在线播放 |