可以誇張點說,如果你不會拖拽,你不是一個合格的前端開發。
回想下,以前我們是怎么實現拖拽的,主要有以下幾步:
1.目標元素綁定mousedown事件,記錄下此時鼠標位置和拖拽元素的位置差,分別是 diffX ,diffY
2.在mousedown中綁定 document的mousemove 以及mouseup
3.在mousemove中計算拖拽元素的位置: x = event.clientX - diffX ,y = event.clientY - diffY
4.mouseup時中銷毀綁定的 document mousemove 和mouseup事件,銷毀拖拽元素
我們也知道,當一個元素拖拽的時候,鼠標順序依次:mousedown,mousemove,mouseup,click , 如果一個元素既可以點擊,又需要拖拽,悲劇就發生了。可能導致,我們拖着拖着發生了點擊事件,頁面跳轉了。這時候,我們通常會采用延時操作,避免誤操作。總之,處理起來是挺麻煩的。
現在好了,有了html5 drag,瀏覽器自動幫我們處理好了。
要讓一個元素支持拖拽,首先我們需要在標簽上標示出來:
<div draggable="true"></div>
*[draggable = true] { -khtml-user-drag: element;}
元素在拖放過程中觸發的事件
先列下拖拽過程中可能觸發的事件,如下:
- dragstart:事件主體是被拖放元素,在開始拖放被拖放元素時觸發,。
- darg:事件主體是被拖放元素,在正在拖放被拖放元素時觸發。
- dragenter:事件主體是目標元素,在被拖放元素進入某元素時觸發。
- dragover:事件主體是目標元素,在被拖放在某元素內移動時觸發。
- dragleave:事件主體是目標元素,在被拖放元素移出目標元素是觸發。
- drop:事件主體是目標元素,在目標元素完全接受被拖放元素時觸發。
- dragend:事件主體是被拖放元素,在整個拖放操作結束時觸發。
其中事件主體是拖放元素的是,dragstart(開始拖動) 、darg(正在拖放) 、dragend(拖放結束),其他4個事件主體都是目標元素,進入、移動、離開、完全進入四個狀態。
注意:為了減少事件,你可以在事件 ondragenter 的時候 綁定方法 ,而 ondragleave 的時候,刪除 方法。最好不要綁定在 dragover 上,它就像 mouseover ,在拖動的過程中不斷觸發,對於瀏覽器的負擔就很大了,瀏覽器還有可能崩潰。
$('.test').on('dragstart',function(e){
console.log('start');
});
$('.test').on('dragend',function(){
console.log('end');
})
如此,就可以讓元素拖動了。需要注意的是,drag系列事件不能跟mousemove共存,只能取其一。
有了HTML5 drag API,判斷拖拽元素跟其他dom元素相交變得容易起來了,只需要:
$('.drop-area').on('dragover',function(e){
console.log('dragover');
e.preventDefault();
});
$('.drop-area').on('drop',function(e){
console.log('drop');
});
需要注意的是,必須寫上紅色部分,如果不阻止默認事件,drop事件將不會觸發。關於這點,可以去w3c查看。
dataTransfer對象
只有簡單的拖放而沒有數據變化是沒有什么用的。為了在拖放操作時實現數據交換HTML5定義了dataTransfer對象來傳遞拖拽的數據。
因為它是事件對象的屬性,所以只能在拖放事件的事件處理程序中訪問dataTransfer對象。在事件處理程序中,可以使用這個對象的屬性和方法來 完善拖放功能。
getData()和setData()
dataTransfer對象有 getData()和setData()兩個主要方法,操作dataTransfer中攜帶的數據。不難想象,getData()可以取得由setData()保存的值。setData()方法的第一個參數,也是getDAta()方法唯一的一個參數,表示保存的數據類型。
IE只定義了“text”和“URL”兩種有效的數據類型,而HTML5則對此加以擴展,允許指定各種MIME類型。考慮到向后兼容,HTML5也支持“text”和“URL”,但這兩種類型會被映射為“text/plain”和“text/uri-list”。如下所示:
- text/html:文本文字格式
- text/plain:HTML代碼格式
- text/xml:XML字符格式
- text/url-list:URL格式列表
實際上,dataTransfer對象可以為每種MIME類型都保存一個值。換句話說,同時在這個對象中保存了一段文本和一個URL不會有任何問題。不過,保存在dataTransfer對象中的數據只能在drop事件處理程序中讀取。如果在ondrop處理程序中沒有讀到數據,那就是dataTransfer對象已經被銷毀,數據也丟失了。
在拖動文本框中的文本時,瀏覽器會調用setData()方法,將拖動的文本以“text”格式保存在dataTransfer對象中。類似地,在拖放鏈接或圖像時,會調用setData()方法並保存URL。然后,在這些元素被拖放到放置目標時,就可以通過getData()讀到這些數據。當然,作為開發人員,你也可以在dragstart事件處理程序中調用setData(),手工保存自己要傳輸的數據,以便將來使用。
將數據保存為文本和保存為URL是有區別的。如果將數據保存為文本格式,那么數據不會得到任何特殊處理。而如果將數據保存為URL,瀏覽器會將其當成網頁中的鏈接。換句話說,如果你把它放置到另一個瀏覽器窗口中,瀏覽器就會打開該URL。
Firefox在其第5個版本之前不能正確地將“URL”和“text”映射為“text/uri-list”和“text/plain”。但是卻能把“Text”映射為“text/plain”。為了更好地在跨瀏覽器的情況下從dataTransfer對象取得數據,最好在取得URL數據時檢測兩個值,而在取得文本數據時使用“text”。
var dataTransfer =event.dataTransfer;//讀取URLvar url = dataTransfer.getData("url")|| dataTransfer.getData("text/uri-list");//讀取文本var text = dataTransfer.getData("Text");
注意:一定要把短數據類型放在前面,因為IE 10及之前的版本仍然不支持擴展的MIME類型名,而它們在遇到無法識別的數據類型時,會拋出錯誤。
使用 setDragImage 方法設置拖放圖標
在HTML5中,一個元素在被拖放時,還可以自定義拖放元素的鼠標圖標。調用格式如下:
setDragImage(Element img,long x,long y);setDragImage調用格式
img表示拖放時的 <> 元素的圖標,x 表示圖標距離鼠標指針的x軸方向的偏移值,y表示圖標距離鼠標指針y軸方向的偏移值。
使用 effectAllowed 和 dropEffect 屬性設置拖放效果
dataTransfer對象的兩個屬性:dropEffect和effectAllowed,能通過它來確定被拖動的元素以及作為放置目標的元素能夠接受什么操作。結合effectAllowed 和 dropEffect 這兩個屬性,可以自定義拖放過程中的效果。兩個屬性雖然都是為了實現同一功能,但綁定的元素不同:effectAllowed屬性作用於被拖放元素;而 dropEffect 屬性作用於目標元素,
其中,通過dropEffect屬性可以知道被拖動的元素能夠執行哪種放置行為。這個屬性有下列4個可能的值。
- none:不能把拖動的元素放在這里。這是除文本框之外所有元素的默認值。
- move:應該把拖動的元素移動到放置目標
- copy:應該把拖動的元素復制到放置目標
- link:表示放置目標會打開拖動的元素(但拖動的元素必須是一個鏈接,有URL)。
在把元素拖動到放置目標上時,以上每一個值都會導致光標顯示為不同的符號。然而,要怎樣實現光標所指示的動作完全取決於你。換句話說,如果你不介入,沒有什么會自動地移動、復制,也不會打開鏈接。總之,瀏覽器只能幫你改變光標的樣式,而其它的都要靠你自己來實現。要使用dropEfect屬性,必須在ondraggenter事件處理程序中針對放置目標來設置它。
dropEffect屬性只有搭配effectAllowed屬性才有用。effectAllowed屬性表示允許拖放元素的哪種dropEffect,effectAllowed屬性可能的值如下。
- uninitialized:沒有該被拖動元素放置行為。
- none:被拖動的元素不能有任何行為。
- copy:只允許值為“copy”的dropEffect。
- link:只允許值為“link”的dropEffect。
- move:只允許值為“move”的dropEffect。
- copyLink:允許值為“copy”和“link”的dropEffect。
- copyMove:允許值為“copy”和”link”的dropEffect。
- linkMove:允許職位“link”和”move”的dropEffect。
- all:允許任意dropEffect。
必須在ondraggstart事件處理程序中設置effectAllowed屬性。
假設你想允許用戶把文本框中的文本拖放到一個<div>元素中。首先,必須將dropEffect和effectAllowed設置為”move”。但是,由於<div>元素的放置事件的默認行為是什么也不做,所以文本不可能自動移動。重寫這個默認行為,就能從文本框中移走文本。然后你就可以自己編寫代碼將文本插入到<div>中,這樣整個拖放操作就完成了。如果將dropEffect和effectAllowed的值設置為”copy”,那就不會自動移走文本框中的文本。
其它屬性
- addElement:事件主體是被拖放元素,為拖動操作添加一個元素。添加這個元素只影響數據(即增加作為拖動源而影響回調的對象),不會影響拖動操作時頁面元素的外觀。在寫作文本時,只有Firefox 3.5+實現了這個方法。
- clearData:事件主體是目標元素,清除以特定格式保存的數據。實現這個方法的瀏覽器有IE、Firefox 3.5、Chrome和Safari 4+。
- types:當前保存的數據類型。這是一個類似數組的集合,以“text”這樣的字符串形式保存着數據類型。實現這個屬性的瀏覽器有IE10+、Firefox 3.5+和Chrome。
支持draggable屬性的瀏覽器有IE10+、Firefox 4+、Safari 5+和Chrome。Opera 11.5以及之前的版本都不支持HTML5的拖放功能。另外,為了讓Firefox 支持可拖動屬性,還必須添加一個ondragstart事件處理程序,並在dataTransfer對象中保存了一些信息。
