HTML5 — 让拖放变的流行起来
在?HTML5?出現(xiàn)之前,頁面元素的拖放需要監(jiān)聽 mousedown、mouseover 以及 mouseup 等一系列事件,然后改變?cè)氐南鄬?duì)位置來實(shí)現(xiàn)這一效果。HTML DnD(Drag-and-Drop)API 的出現(xiàn),使得拖放變的簡單。但是由于 DnD 尚處在草案階段,各瀏覽器對(duì)其規(guī)范并未統(tǒng)一,有些事件在不同瀏覽器中會(huì)出現(xiàn)不同效果。
要使用 DnD,需要明確兩件事情,一是需要拖動(dòng)的元素,二是可放置拖動(dòng)元素的位置。拖放無非是將元素從一個(gè)位置拖到另一個(gè)位置。
Drag
首先我們需要指定要拖動(dòng)的元素,設(shè)置方式很簡單,給該 DOM 元素設(shè)置 draggable 屬性,屬性值設(shè)置為 true。比如這樣:
<img src="images/0.jpg" draggable="true" id="img0"/>
事實(shí)上,以上代碼多此一舉了,頁面中的圖片(img)、鏈接(帶 href 的 a 標(biāo)簽)以及文本默認(rèn)即為可拖動(dòng)。為了統(tǒng)一,最好還是都加上該 draggable 屬性為好。draggable 屬性還有兩個(gè)值,分別是 false 和 auto,顧名思義,false 即設(shè)置為不可拖動(dòng),auto 即為瀏覽器默認(rèn)值。
當(dāng)我們左鍵點(diǎn)擊(按下)可拖動(dòng)的 DOM 元素,輕輕移動(dòng),即觸發(fā) ondragstart 事件,該事件只會(huì)觸發(fā)一次。通常我們會(huì)在 ondragstart 事件中記錄正在被拖動(dòng)的元素信息(ondrop 的時(shí)候好對(duì)其進(jìn)行處理)。比如 demo 中記錄了正在被拖動(dòng)的元素 id:
for (var i = lis.length; i--; ) {
lis[i].ondragstart = function(e) {
e.dataTransfer.setData('id', e.target.id);
};
}
? ? ? ondragstart 事件觸發(fā)后,直到拖放事件結(jié)束,會(huì)一直觸發(fā) ondrag 事件。
Drop
其次我們需要明確被拖動(dòng)元素可放置的位置,ondragover 事件規(guī)定在何處放置被拖動(dòng)的數(shù)據(jù)。
默認(rèn)地,無法將元素放置到其他元素中,如果需要設(shè)置允許放置,我們必須阻止對(duì)元素的默認(rèn)處理方式:
var dus = document.querySelector('.dustbin');
dus.ondragover = function(e) {
e.preventDefault();
};
當(dāng)元素被拖動(dòng)到某一元素上時(shí),即會(huì)觸發(fā)后者的 ondrop 事件,如果需要正確觸發(fā) ondrop 事件,還需要取消一些 DnD 事件的默認(rèn)行為:
dus.ondrop = function(e) {
// 調(diào)用 preventDefault() 來避免瀏覽器對(duì)數(shù)據(jù)的默認(rèn)處理(drop 事件的默認(rèn)行為是以鏈接形式打開)
e.preventDefault();
e.stopPropagation(); // 兼容ff
var id = e.dataTransfer.getData('id')
, node = document.getElementById(id);
node.parentNode.removeChild(node);
};
有些文獻(xiàn)中說要取消 ondragenter() 事件的默認(rèn)行為,樓主在實(shí)際操作中并未發(fā)現(xiàn)這點(diǎn)。
事件
上面已經(jīng)提到了 DnD 中的三個(gè)事件,dragstart、dragover 以及 drop,其實(shí) DnD 還有幾個(gè)事件,它們的發(fā)生順序是:
dragstart(drag元素) -> drag(drag元素) -> dragenter(drop元素) -> dragover(drop元素) -> dragleave(drop元素) -> drop(drop元素) -> dragend(drag元素)
不難理解,拖放事件開始時(shí)觸發(fā) ondragstart 事件,當(dāng)被拖動(dòng)元素進(jìn)入可放置的元素時(shí),觸發(fā) ondragenter 事件(ondragenter 并不是在兩個(gè)元素相交時(shí)即觸發(fā),而是該被拖拽元素在目標(biāo)元素上移動(dòng)一段時(shí)間后才觸發(fā)),之后一段事件會(huì)持續(xù)觸發(fā) ondragover 事件(可參考 mouseover),當(dāng)被拖動(dòng)元素離開可放置元素的一瞬間,觸發(fā) ondragleave(和 ondragenter 對(duì)應(yīng)) 事件,當(dāng)松開鼠標(biāo)并且 被拖拽元素正好在可放置元素上時(shí),觸發(fā) ondrop 事件,當(dāng)拖放事件結(jié)束時(shí),觸發(fā) ondragend(和 ondragstart 對(duì)應(yīng)) 事件,無論拖放操作是否成功,均會(huì)觸發(fā)該事件。
dataTransfer
拖動(dòng)過程中,回調(diào)函數(shù)接受的事件參數(shù),有一個(gè) dataTransfer 屬性。它指向一個(gè)對(duì)象,包含了與拖動(dòng)相關(guān)的各種信息。
dataTransfer 對(duì)象主要有兩種方法:getData() 和 setData(),需要注意的是,只有在 dragstart 以及 drop 事件中使用這兩個(gè)方法。不難想象,getData() 可以取得由 setData() 保存的值。
setData() 方法的第一個(gè)參數(shù),也是 getData() 方法唯一的一個(gè)參數(shù),是個(gè)字符串,表示保存的數(shù)據(jù)類型,取值為 ‘text’ 或 ‘URL’。IE 只定義了 ‘text’ 和 ‘URL’ 兩種有效的數(shù)據(jù)類型, 而 HTML5 則對(duì)此加以擴(kuò)展,允許指定各種 MIME 類型。
在拖動(dòng)文本框中的文本時(shí),瀏覽器會(huì)自動(dòng)調(diào)用 setData() 方法,將拖動(dòng)的文本以 ‘text’ 格式保存在 dataTransfer 對(duì)象中,類似地,在拖放鏈接或者圖像時(shí),會(huì)自動(dòng)調(diào)用 setData() 將 URL 信息 保存,如果有需要,在 drop 事件中可以用 getData() 讀取瀏覽器保存的值。
但是這似乎并沒有什么卵用,我們?cè)趯?shí)際開發(fā)中多數(shù)還是對(duì) DOM 的操作,于是多數(shù)情況下我們?cè)?dragstart 事件處理程序中調(diào)用 setData(),手工保存自己要傳輸?shù)臄?shù)據(jù),然后在 drop 事件中讀取, 有點(diǎn)像 jQuery 的 data 事件。
dropEffect 與 effectAllowed
dropEffect 和 effectAllowed 是前面說的 dataTransfer 對(duì)象的兩個(gè)屬性,有啥用?簡單地說,有兩個(gè)用處,一是可以設(shè)置元素被拖拽時(shí)的鼠標(biāo)樣式,二是可以設(shè)置元素是否可被放置。
這里我測試了三款瀏覽器,chrome、ff 以及 uc,chrome 和 uc 表現(xiàn)相似。
一般我們將元素脫離原來的位置,鼠標(biāo)手勢會(huì)變成 “禁手”,直到元素被拖到可放置區(qū)域上。
但是 ff 不然,在 ff 中,元素在拖動(dòng)的過程中不會(huì)顯示 “禁手”。
當(dāng)元素被拖到可放置區(qū)域上時(shí),默認(rèn)鼠標(biāo)手勢如下。
其實(shí)通過設(shè)置 dropEffect 和 effectAllowed 總共能設(shè)置三種鼠標(biāo)手勢(move, copy,以及 link),分別如下(move 和默認(rèn)貌似一樣):
需要在 ondragstart 方法中設(shè)置 effectAllowed,在 ondragover 方法中設(shè)置 dropEffect。具體可以參考 demo代碼。
我們也可以對(duì) dropEffect 和 effectAllowed 的值進(jìn)行設(shè)定,讓某 drop 元素只能放 move 元素,或者 copy 元素等。具體可以看下這篇,HTML5魔法堂:全面理解Drag & Drop API,講的很好。取值也可以參考高程 484 頁。
總之要知道的是,DnD 并不會(huì)幫你完成 copy 或者 move 的任何操作,而是需要用戶在 DnD 過程中,記錄需要操作的對(duì)象信息,然后在 drop 事件中完成 copy 或者 move 等的操作。
Tricks
還有幾個(gè)實(shí)踐過程中發(fā)現(xiàn)的問題。
將 Demo 在 ff 中打開,圖片拖到空處,會(huì)自動(dòng)在新標(biāo)簽中打開圖片,盡管我已經(jīng)在各種事件中加上了 preventDefault(),尚不清楚原因。
如果可拖拽元素,初始在一個(gè)可放置元素內(nèi)部,先把元素拖出去,再放回來,將會(huì)觸發(fā) ondrop 事件,但是 e.target 卻是被拖拽的元素。如果放置在其他元素,target 會(huì)指向被放置的元素,而不是拖拽元素。這點(diǎn)可以通過判斷 target 元素得到解決。關(guān)于這點(diǎn)可以看下 w3cschool 的這個(gè) demo,打開控制臺(tái),將圖片拖出去,再拖回來,控制臺(tái)會(huì)打印出錯(cuò)誤,顯然代碼沒有考慮到這一點(diǎn)。
繼續(xù)相關(guān)文章:http://wex5.com/cn/2016/01/
本文由WeX5君整理,WeX5一款開源免費(fèi)的html5開發(fā)工具,H5 App開發(fā)就用WeX5!
轉(zhuǎn)載于:https://www.cnblogs.com/huzigege/p/5148595.html
總結(jié)
以上是生活随笔為你收集整理的HTML5 — 让拖放变的流行起来的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Open*** 安装脚本
- 下一篇: HTML5本地存储之Web Storag