欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
JavaScript 拖放效果

拖放效果,也叫拖拽、拖動(dòng),學(xué)名Drag-and-drop ,是最常見(jiàn)的js特效之一。
如果忽略很多細節,實(shí)現起來(lái)很簡(jiǎn)單,但往往細節才是難點(diǎn)所在。
這個(gè)程序的原型是在做圖片切割效果的時(shí)候做出來(lái)的,那時(shí)參考了好幾個(gè)同類(lèi)的效果,跟muxrwcBlueDestiny學(xué)習了不少東西。
雖然每次整理都覺(jué)得很好了,不過(guò)每隔一段時(shí)間又會(huì )發(fā)現得某個(gè)地方可以改善,某個(gè)地方有錯誤,某些需求需要實(shí)現,就像自己學(xué)習的知識那樣。

這里考慮到有的人可能只需要簡(jiǎn)單的拖放,所以有一個(gè)簡(jiǎn)化版的拖放SimpleDrag,方便學(xué)習。

效果預覽

在maxthon下如果開(kāi)啟廣告過(guò)濾的話(huà)很可能會(huì )被過(guò)濾掉(不知有什么方法可以避免)。


拖放狀態(tài):結束拖放

 

程序說(shuō)明

【程序原理】

這里以SimpleDrag為例說(shuō)一下基本原理。

首先初始化程序中要一個(gè)拖放對象:

this.Drag = $(drag);


還要兩個(gè)參數在開(kāi)始時(shí)記錄鼠標相對拖放對象的坐標:

this._x = this._y = 0;


還有兩個(gè)事件對象函數用于添加移除事件:

this._fM = BindAsEventListener(thisthis.Move);
this._fS = Bind(thisthis.Stop);


分別是拖動(dòng)程序和停止拖動(dòng)程序。
拖放對象的position必須是absolute絕對定位:

this.Drag.style.position = "absolute";


最后把Start開(kāi)始拖放程序綁定到拖放對象mousedown事件:

addEventHandler(this.Drag, "mousedown", BindAsEventListener(thisthis.Start));


鼠標在拖放對象按住,就會(huì )觸發(fā)Start程序,主要是用來(lái)準備拖動(dòng),在這里記錄鼠標相對拖放對象的坐標:

this._x = oEvent.clientX - this.Drag.offsetLeft;
this._y = oEvent.clientY - this.Drag.offsetTop;


并把_fM拖動(dòng)程序和_fS停止拖動(dòng)程序分別綁定到document的mousemove和mouseup事件:

addEventHandler(document, "mousemove"this._fM);
addEventHandler(document, 
"mouseup"this._fS);


綁定到document可以保證事件在整個(gè)窗口文檔中都有效。

當鼠標在文檔上移動(dòng)時(shí),就會(huì )觸發(fā)Move程序了,這里就是實(shí)現拖動(dòng)的程序。
通過(guò)現在鼠標的坐標值跟開(kāi)始拖動(dòng)時(shí)鼠標相對的坐標值的差就可以得到拖放對象應該設置的left和top了:

this.Drag.style.left = oEvent.clientX - this._x + "px";
this.Drag.style.top = oEvent.clientY - this._y + "px";


最后放開(kāi)鼠標后就觸發(fā)Stop程序結束拖放。
這里的主要作用是把Start程序中給document添加的事件移除:

removeEventHandler(document, "mousemove"this._fM);
removeEventHandler(document, 
"mouseup"this._fS);


這樣一個(gè)簡(jiǎn)單的拖放程序就做好了,下面說(shuō)說(shuō)其他擴展和細節部分。


【拖放鎖定】

鎖定分三種,分別是:水平方向鎖定(LockX)、垂直方向鎖定(LockY)、完全鎖定(Lock)。
這個(gè)比較簡(jiǎn)單,水平和垂直方向的鎖定只要在Move判斷是否鎖定再設置left和top就行,如果是完全鎖定就直接返回。

if(!this.LockX){ this.Drag.style.left = 
; }
if(!this.LockY){ this.Drag.style.top = 
; }


【觸發(fā)對象】

觸發(fā)對象是用來(lái)觸發(fā)拖放程序的,程序中通過(guò)Handle屬性設置。有的時(shí)候不需要整個(gè)拖放對象都用來(lái)觸發(fā),這時(shí)就需要觸發(fā)對象了。
使用了觸發(fā)對象后,進(jìn)行移動(dòng)的還是拖放對象,只是用觸發(fā)對象來(lái)觸發(fā)拖放(一般的使用是把觸發(fā)對象放到拖放對象里面)。
ps:觸發(fā)對象的另一個(gè)用法是通過(guò)設置相同的Handle,實(shí)現一個(gè)觸發(fā)對象同時(shí)拖放多個(gè)拖放對象。

【范圍限制】

要設置范圍限制必須先把Limit設為true。范圍限制分兩種,分別是固定范圍和容器范圍限制,主要在Move程序中設置。
原理是當比較的值超過(guò)范圍時(shí),修正left和top要設置的值使拖放對象能保持在設置的范圍內。

【固定范圍限制】

容器范圍限制就是指定上下左右的拖放范圍。
各個(gè)屬性的意思是:
上(mxTop):top限制;
下(mxBottom):top+offsetHeight限制;
左(mxLeft):left限制;
右(mxRight):left+offsetWidth限制。

如果范圍設置不正確,可能導致上下或左右同時(shí)超過(guò)范圍的情況,程序中有一個(gè)Repair程序用來(lái)修正范圍參數的。
Repair程序會(huì )在程序初始化和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的最小范圍值。

根據范圍參數修正移動(dòng)參數:

iLeft = Math.max(Math.min(iLeft, mxRight - this.Drag.offsetWidth), mxLeft);
iTop 
= Math.max(Math.min(iTop, mxBottom - this.Drag.offsetHeight), mxTop);


對于左邊上邊要取更大的值,對于右邊下面就要取更小的值。

【容器范圍限制】

容器范圍限制的意思就是把范圍限制在一個(gè)容器_mxContainer內。
要注意的是拖放對象必須包含在_mxContainer中,因為程序中是使用相對定位來(lái)設置容器范圍限制的(如果是在容器外就要用絕對定位,這樣處理就比較麻煩了),還有就是容器空間要比拖放對象大,這個(gè)就不用說(shuō)明了吧。
原理跟固定范圍限制差不多,只是范圍參數是根據容器的屬性的設置的。

當設置了容器,在Repair程序會(huì )自動(dòng)把position設為relative來(lái)相對定位:

!this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer.style.position = "relative");


ps:其中CurrentStyle是用來(lái)獲取最終樣式(詳細看這里的最終樣式部分)。

注意如果在程序執行之前設置過(guò)拖放對象的left和top而容器沒(méi)有設置relative,在自動(dòng)設置relative時(shí)會(huì )發(fā)生移位現象,所以程序在初始化時(shí)就執行一次Repair程序防止這種情況。因為offsetLeft和offsetTop要在設置relative之前獲取才能正確獲取值,所以在Start程序中Repair要在設置_x和_y之前執行。

由于是相對定位,對于容器范圍來(lái)說(shuō)范圍參數上下左右的值分別是0、clientHeight、0、clientWidth。
clientWidth和clientHeight是容器可視部分的寬度和高度(詳細參考這里)。
為了容器范圍能兼容固定范圍的參數,程序中會(huì )獲取容器范圍和固定范圍中范圍更小的值:

Code


因為設置相對定位的關(guān)系,容器_mxContainer設置過(guò)后一般不要取消或修改,否則很容易造成移位異常。


【鼠標捕獲】

我在一個(gè)拖放實(shí)例中看到,即使鼠標移動(dòng)到瀏覽器外面,拖放程序依然能夠執行,仔細查看后發(fā)現是用了setCapture。
鼠標捕獲(setCapture)是這個(gè)程序的重點(diǎn),作用是將鼠標事件捕獲到當前文檔的指定的對象。這個(gè)對象會(huì )為當前應用程序或整個(gè)系統接收所有鼠標事件。
使用很簡(jiǎn)單:

this._Handle.setCapture();

setCapture捕獲以下鼠標事件:onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout。
程序中主要是要捕獲onmousemove和onmouseup事件。
msdn的介紹中還說(shuō)到setCapture有一個(gè)bool參數,用來(lái)設置在容器內的鼠標事件是否都被容器捕獲。
容器就是指調用setCapture的對象,大概意思就是:
參數為true時(shí)(默認)容器會(huì )捕獲容器內所有對象的鼠標事件,即容器內的對象不會(huì )觸發(fā)鼠標事件(跟容器外的對象一樣);
參數為false時(shí)容器不會(huì )捕獲容器內對象的鼠標事件,即容器內的對象可以正常地觸發(fā)事件和取消冒泡。
而對于容器外的鼠標事件無(wú)論參數是什么都會(huì )被捕獲,可以用下面這個(gè)簡(jiǎn)單的例子測試一下(ie):

Code


這里的參數是true,一開(kāi)始body會(huì )捕獲所有鼠標事件,即使鼠標經(jīng)過(guò)div也不會(huì )觸發(fā)onmousemove事件。
換成false的話(huà),div就可以捕獲鼠標事件,就能觸發(fā)div的onmousemove事件了。

拖放結束后還要使用releaseCapture釋放鼠標,這個(gè)可以放在Stop程序中:

this._Handle.releaseCapture();


setCapture是ie的鼠標捕獲方法,對于ff也有對應的captureEvents和releaseEvents方法。
但這兩個(gè)方法只能由window來(lái)調用,而且muxrwc說(shuō)這兩個(gè)方法在DOM2里已經(jīng)廢棄了,在ff里已經(jīng)沒(méi)用了。
不過(guò)ff里貌似會(huì )自動(dòng)設置取消鼠標捕獲,但具體的情形就不清楚了,找不到一個(gè)比較詳細的介紹,誰(shuí)有這方面的資料記得告訴我啊。

下面都是我的猜測,ff的鼠標捕獲相當于能自動(dòng)設置和釋放的document.body.setCapture(false)。
因為我測試下面的程序,發(fā)現ie和ff效果是差不多的:
ie:

Code


ff:

Code

可惜沒(méi)有權威的資料參考就只能猜猜了,還有很多還沒(méi)有理解的地方以后再研究拉。

注意ff2下的鼠標捕獲有一個(gè)bug,當拖放對象內部沒(méi)有文本內容并拖放到瀏覽器外時(shí)捕獲就會(huì )失效。
給拖放對象插入一個(gè)空文本,例如<font size='1px'> </font>就可以解決,不過(guò)這個(gè)bug在ff3已經(jīng)修正了。


【焦點(diǎn)丟失】

一般情況下,鼠標捕獲都能正常捕獲事件,但如果瀏覽器窗口的焦點(diǎn)丟失就會(huì )導致捕獲失效。
我暫時(shí)測試到會(huì )導致焦點(diǎn)丟失的操作包括切換窗口(包括alt+tab),alert和popup等彈出窗體。
當焦點(diǎn)丟失時(shí)應該同時(shí)執行Stop程序結束拖放,但當焦點(diǎn)丟失就不能捕獲mouseup事件也就是不能觸發(fā)_fS。
還好ie有onlosecapture事件會(huì )在捕獲失效時(shí)觸發(fā),針對這個(gè)情況可以這樣設置:

addEventHandler(this._Handle, "losecapture"this._fS);


并在Stop程序中移除:

removeEventHandler(this._Handle, "losecapture"this._fS);

但ff沒(méi)有類(lèi)似的方法,不過(guò)muxrwc找到一個(gè)替代losecapture的window.onblur事件,那么可以在Start程序中設置:

addEventHandler(window, "blur"this._fS);


在Stop程序中移除:

removeEventHandler(window, "blur"this._fS);

那ie也有window.onblur事件,用window.onblur代替losecapture不就可以省一段代碼了嗎。
接著(zhù)我做了一些測試,發(fā)現基本上觸發(fā)losecapture的情況都會(huì )同時(shí)觸發(fā)window.onblur,看來(lái)真的可以。
于是我修改程序用window.onblur代替losecapture,但測試后就出問(wèn)題了,我發(fā)現如果我用alt+tab切換到另一個(gè)窗口,拖動(dòng)還可以繼續,但這個(gè)時(shí)候應該是已經(jīng)丟失焦點(diǎn)了。

于是我逐一排除測試和程序代碼,結果發(fā)現如果使用了DTD,那么window.onblur會(huì )在再次獲得焦點(diǎn)時(shí)才會(huì )觸發(fā)。
大家可以用下面這段代碼測試:

<!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是不理想的了。


【取消默認動(dòng)作】

對選擇狀態(tài)的文本內容、連接和圖片等進(jìn)行拖放操作會(huì )觸發(fā)系統的默認動(dòng)作,例如ie中拖動(dòng)圖片鼠標會(huì )變成禁止操作狀態(tài),這樣會(huì )導致這個(gè)拖放程序執行失敗。

不過(guò)ie在設置了setCapture之后,通過(guò)用戶(hù)界面用鼠標進(jìn)行拖放操作和內容選擇都會(huì )被禁止。
意思就是setCapture之后就不能對文檔內容進(jìn)行拖放和選擇,注意這里的拖放是指系統的默認動(dòng)作,例如ondragstart就不會(huì )被觸發(fā)。
不過(guò)如果setCapture的參數是false的話(huà),容器內的對象還是可以觸發(fā)事件的(具體看鼠標捕獲部分),所以setCapture的參數要設成true或保留默認值。

而ff的鼠標捕獲沒(méi)有這個(gè)功能,但可以用preventDefault來(lái)取消事件的默認動(dòng)作來(lái)解決:

oEvent.preventDefault();


ps:據說(shuō)使用preventDefault會(huì )出現mouseup丟失的情況,但我在ff3中測試沒(méi)有發(fā)現,如果各位發(fā)現任何mouseup丟失的情況,務(wù)必告訴我啊。


【清除選擇】

ie在設置setCapture之后內容選擇都會(huì )被禁止,但也因此不會(huì )清除在設置之前就已經(jīng)選擇的內容,而且設置之后也能通過(guò)其他方式選擇內容,
例如用ctrl+a來(lái)選擇內容。
ps:onkeydown、onkeyup和onkeypress事件不會(huì )受到鼠標捕獲影響。
而ff在mousedown時(shí)就能清除原來(lái)選擇的內容,但拖動(dòng)鼠標,ctrl+a時(shí)還是會(huì )繼續選擇內容。
不過(guò)在取消了系統默認動(dòng)作之后,這樣的選擇并不會(huì )對拖放操作造成影響,這里設置主要還是為了更好的體驗。

以前我用禁止拖放對象被選擇的方法來(lái)達到目的,即ie中設置拖放對象的onselectstart返回false,在ff中設置樣式MozUserSelect(css:-moz-user-select)為none。
但這種方法只能禁止拖放對象本身被選擇,后來(lái)找到個(gè)更好的方法清除選擇,不但不影響拖放對象的選擇效果,還能對整個(gè)文檔進(jìn)行清除:
ie:document.selection.empty()
ff:window.getSelection().removeAllRanges()
為了防止在拖放過(guò)程中選擇內容,所以把它放到Move程序中,下面是兼容的寫(xiě)法:

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();


【margin】

還有一個(gè)情況,當拖放對象設置了margin,那么拖放的時(shí)候就會(huì )錯位(給SimpleDrag的拖放對象設置margin就可以測試)。
原因是在Start程序設置_x和_y時(shí)是使用offset獲取的,而這個(gè)值是包括margin的,所以在設置left和top之前要減去這個(gè)margin。
但如果在Start程序中就去掉margin那么在Move程序中設置范圍限制時(shí)就會(huì )計算錯誤,
所以最好是在Start程序中獲取值:

this._marginLeft = parseInt(CurrentStyle(this.Drag).marginLeft) || 0;
this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0;


在Move程序中設置值:

this.Drag.style.left = iLeft - this._marginLeft + "px";
this.Drag.style.top = iTop - this._marginTop + "px";


要注意margin要在范圍修正之后再設置,否則會(huì )錯位。

【透明背景bug】

在ie有一個(gè)透明背景bug(不知算不算bug),可以用下面的代碼測試:

Code


會(huì )發(fā)現背景點(diǎn)擊觸發(fā)不了事件,不過(guò)點(diǎn)擊邊框的話(huà)還是可以觸發(fā)。
為什么呢?再用下面的代碼測試:

Code

應該能看出個(gè)大概了,下面兩個(gè)div超出body(即超出紅色框)的部分就觸發(fā)不了事件。
也就是說(shuō)當觸發(fā)事件的點(diǎn),在body以外,而背景又是透明的,那么就會(huì )誤認為觸發(fā)點(diǎn)是在了body外空白的地方,所以觸發(fā)不了事件。
那解決的方法就是,使事件觸發(fā)點(diǎn)保持在body內,或者設置一個(gè)非透明背景。

那程序中只要給拖放對象設一個(gè)背景色就可以解決了,但有時(shí)需求正好是要透明(例如切割效果),那怎么辦呢?
首先想到的是加上背景色后設置完全透明,但這樣連邊框,容器內的對象等都完全透明了,這個(gè)不好。
我想到的一個(gè)解決方法是在容器里面加一個(gè)層,覆蓋整個(gè)容器,并設置背景色和完全透明:

with(this._Handle.appendChild(document.createElement("div")).style){
    width 
= height = "100%"; backgroundColor = "#fff"; filter = "alpha(opacity:0)";
}


當發(fā)現程序有這個(gè)bug出現,把程序可選參數Transparent設為true就會(huì )自動(dòng)插入這樣一個(gè)層了。

【iframe】

如果頁(yè)面上有嵌入iframe,那就要注意了,因為鼠標捕獲在iframe上會(huì )有問(wèn)題。

例如在拖放容器內的一個(gè)iframe上快速移動(dòng)拖放,或者鼠標拖動(dòng)到容器外的一個(gè)iframe上,反正就是鼠標在iframe上(注意沒(méi)有其他元素隔開(kāi)),就會(huì )出問(wèn)題:
首先是捕獲的失效,鼠標在iframe上,就拖不動(dòng)了,這個(gè)在ie和ff都是一樣;
其次ie里在iframe多摩擦幾次,還可能導致ie死掉(原因不明)。

這里我想到兩種方法:
隱藏頁(yè)面的iframe;
每個(gè)iframe用一個(gè)透明的層遮??;
用一個(gè)透明的層把整個(gè)頁(yè)面遮住。

第一種方法難度不大,但有時(shí)候不希望iframe被隱藏(例如iframe顯示的是一些必須顯示的信息);
第二種方法很麻煩,要計算好每個(gè)iframe的位置和大??;
第三種方法我比較推薦,也比較簡(jiǎn)單。

我在仿LightBox內容顯示效果做的那個(gè)覆蓋層正好能應用在這里,首先實(shí)例化一個(gè)透明的覆蓋層:

var ol = new OverLay({ Opacity: 0 });


然后在onStart和onStop事件中添加ol.Show()和ol.Close()來(lái)顯示和隱藏覆蓋層就可以了,這樣只要不是在iframe觸發(fā)拖放就沒(méi)有問(wèn)題了。

有其他更好的方法也請各位指教。

暫時(shí)就研究到這里,想不到小小的拖放就有這么多的學(xué)問(wèn)。
還有滾屏等這些都還沒(méi)考慮到呢,等以后有需要了再來(lái)研究拉。

使用說(shuō)明

實(shí)例化時(shí)只需要一個(gè)參數,就是拖放對象:
new SimpleDrag("idDrag");

有以下這些可選參數和屬性:
屬性:默認值//說(shuō)明
Handle:"",//設置觸發(fā)對象(不設置則使用拖放對象)
Limit:false,//是否設置范圍限制(為true時(shí)下面參數有用,可以是負數)
mxLeft:0,//左邊限制
mxRight:9999,//右邊限制
mxTop:0,//上邊限制
mxBottom:9999,//下邊限制
mxContainer:"",//指定限制在容器內
LockX:false,//是否鎖定水平方向拖放
LockY:false,//是否鎖定垂直方向拖放
Lock:false,//是否鎖定
Transparent: false,//是否透明
onStart:function(){},//開(kāi)始移動(dòng)時(shí)執行
onMove:function(){},//移動(dòng)時(shí)執行
onStop:function(){}//結束移動(dòng)時(shí)執行

還有屬性Drag是拖放對象,Transparent、Handle和mxContainer初始化后就不能再設置。

程序代碼:

Code


本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
JavaScript拖拽效果關(guān)于鼠標在瀏覽器外面的分析
DELPHI中鼠標的各種操作
VB中的鍵盤(pán)事件、鼠標事件、拖放技術(shù)
實(shí)戰PyQt5: 100
表單及控件屬性一覽表
Authorware7 制作課件及使用技巧
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久