首頁 web前端 js教程 javascript拖放效果深入研究

javascript拖放效果深入研究

Dec 14, 2016 pm 04:05 PM

拖放效果,也叫拖拽,學名Drag-and-drop ,是最常見的js特效之一。
如果忽略很多細節,實作起來很簡單,但往往細節才是困難所在。
這個程式的原型是在做圖片切割效果的時候做出來的,那時參考了好幾個同類的效果,跟muxrwc和BlueDestiny學習了不少東西。
雖然每次整理都覺得很好了,不過每隔一段時間又會發現得某個地方可以改善,某個地方有錯誤,某些需求需要實現,就像自己學習的知識那樣。

這裡考慮到有的人可能只需要簡單的拖放,所以有一個 簡化版的拖放SimpleDrag ,方便學習。

程式原理

這裡以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));

滑鼠在拖曳物件按住,就會觸發程序,主要是用來準備拖曳,在這裡記錄滑鼠相對拖放物件的座標:

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 = ...; }


觸發物件

觸發物件是用來觸發拖放程式的。有的時候不需要整個拖放物件都用來觸發,這時就需要觸發物件了。 

使用了觸發對象後,進行移動的還是拖放對象,只是用觸發對象來觸發拖放(一般的使用是把觸發對象放到拖放對象裡面)。


範圍限制

要設定範圍限制必須先把Limit設為true。範圍限制分兩種,分別是固定範圍和容器範圍限制,主要在Move程式中設定。 

原理是當比較的值超過範圍時,修正left和top要設定的值使拖放物件保持在設定的範圍內。


固定範圍限制

容器範圍限制就是指定上下左右的拖放範圍。

各個屬性的意思是:


上(mxTop):top限制;

下(mxBottom):top+offsetHeight限制;

左(mxLeft):left限制

如果範圍設定不正確,可能導致上下或左右同時超過範圍的情況,程式中有一個Repair程式用來修正範圍參數的。

Repair程式會在程式初始化和Start程式中執行,在Repair程式修正mxRight和mxBottom:

this.mxRight = Math.max(this.mxRight, this.mxLeft + this.Drag.offsetWidth); . 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, mxBot this.Drag.offsetHeight), mxTop);

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

容器范围限制

容器范围限制的意思就是把范围限制在一个容器_mxContainer内。 
要注意的是拖放对象必须包含在_mxContainer中,因为程序中是使用相对定位来设置容器范围限制的(如果是在容器外就要用绝对定位,这样处理就比较麻烦了),还有就是容器空间要比拖放对象大,这个就不用说明了吧。 
原理跟固定范围限制差不多,只是范围参数是根据容器的属性的设置的。

当设置了容器,会自动把position设为relative来相对定位:

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

注意relative要在获取offsetLeft和offsetTop即设置_x和_y之前设置,offset才能正确获取值。

由于是相对定位,对于容器范围来说范围参数上下左右的值分别是0、clientHeight、0、clientWidth。

clientWidth和clientHeight是容器可视部分的宽度和高度(详细参考这里)。 
为了容器范围能兼容固定范围的参数,程序中会获取容器范围和固定范围中范围更小的值:

mxLeft = Math.max(mxLeft, 0); 
mxTop = Math.max(mxTop, 0); 
mxRight = Math.min(mxRight, this._mxContainer.clientWidth); 
mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight);

注意如果在程序执行之前设置过拖放对象的left和top而容器没有设置relative,在自动设置relative时会发生移位现象,所以程序在初始化时就执行一次Repair程序防止这种情况。因为offsetLeft和offsetTop要在设置relative之前获取才能正确获取值,所以在Start程序中Repair要在设置_x和_y之前执行。

因为设置相对定位的关系,容器_mxContainer设置过后一般不要取消或修改,否则很容易造成移位异常。

鼠标捕获

我在一个拖放实例中看到,即使鼠标移动到浏览器外面,拖放程序依然能够执行,仔细查看后发现是用了setCapture。 
鼠标捕获(setCapture)是这个程序的重点,作用是将鼠标事件捕获到当前文档的指定的对象。这个对象会为当前应用程序或整个系统接收所有鼠标事件。 
使用很简单:

this._Handle.setCapture();

setCapture捕获以下鼠标事件:onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout。 
程序中主要是要捕获onmousemove和onmouseup事件。 
msdn的介绍中还说到setCapture有一个bool参数,用来设置在容器内的鼠标事件是否都被容器捕获。
容器就是指调用setCapture的对象,大概意思就是: 
参数为true时(默认)容器会捕获容器内所有对象的鼠标事件,即容器内的对象不会触发鼠标事件(跟容器外的对象一样); 
参数为false时容器不会捕获容器内对象的鼠标事件,即容器内的对象可以正常地触发事件和取消冒泡。 
而对于容器外的鼠标事件无论参数是什么都会被捕获, 
可以用下面这个简单的例子测试一下(ie):

 
 

mouseover
 
<script>document.body.setCapture(); </script> 
 

这里的参数是true,一开始body会捕获所有鼠标事件,即使鼠标经过div也不会触发onmousemove事件。 
换成false的话,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:

 
 

 
<script> <br>document.body.onmousedown=function(){this.setCapture(false)} <br>document.body.onmouseup=function(){this.releaseCapture()} <br>document.onmousemove=function(){aa.innerHTML+=1} <br></script> 
 

ff:

 
 

 
<script> <br/>document.onmousemove=function(){aa.innerHTML+=1} <br/></script> 

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何在微軟Edge中啟用超級拖放模式 如何在微軟Edge中啟用超級拖放模式 Mar 18, 2024 am 09:40 AM

MicrosoftEdge的拖放功能讓您可以輕鬆開啟網頁上的連結或文本,這種功能既實用又省時。要使用此功能,只需將連結或文字拖放到網頁的任意位置即可。本文將向您介紹如何在MicrosoftEdge中啟用或停用超級拖放模式。什麼是MicrosoftEdge中的超級拖放模式?微軟Edge引進了一項名為「超級拖放」的新功能,用戶只需簡單地拖放連結即可在新分頁中快速開啟。只需將連結拖曳到Edge瀏覽器視窗的任何位置即可輕鬆實現。 Edge會自動在一個新的選項卡中載入該連結。此外,用戶還可以根據個人偏

深入探討模型、資料與架構:一份詳盡的54頁高效能大語言模型綜述 深入探討模型、資料與架構:一份詳盡的54頁高效能大語言模型綜述 Jan 14, 2024 pm 07:48 PM

大規模語言模型(LLMs)在許多重要任務中展現了引人注目的能力,包括自然語言理解、語言生成和複雜推理,並對社會產生了深遠的影響。然而,這些出色的能力卻需要大量的訓練資源(如左圖)和較長的推理時間(如右圖)。因此,研究人員需要開發有效的技術手段來解決它們的效率問題。此外,從圖的右邊還可以看出,一些高效率的LLMs(LanguageModels)如Mistral-7B,已經成功應用於LLMs的設計和部署中。這些高效的LLMs在保持與LLaMA1-33B相近的準確性的同時,能夠大大減少推理內存

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

SD社群的I2V-Adapter:無需配置,即插即用,完美相容於圖生視訊插件 SD社群的I2V-Adapter:無需配置,即插即用,完美相容於圖生視訊插件 Jan 15, 2024 pm 07:48 PM

影像到影片生成(I2V)任務是電腦視覺領域的一項挑戰,旨在將靜態影像轉化為動態影片。這個任務的困難在於從單張影像中提取並產生時間維度的動態訊息,同時保持影像內容的真實性和視覺上的連貫性。現有的I2V方法通常需要複雜的模型架構和大量的訓練資料來實現這一目標。近期,快手主導的一項新研究成果《I2V-Adapter:AGeneralImage-to-VideoAdapterforVideoDiffusionModels》發布。該研究引入了一種創新的圖像到視頻轉換方法,提出了一種輕量級適配器模組,即I

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

See all articles