HTML5拖放API Drag and Drop
此文研究Web API中的拖放介面,提供各個屬性和方法的說明,解決拖放過程中的拖拽資料物件儲存和獲取問題。
拖放API作用到兩個目標物件,分別是拖拽目標物件和放置目標物件。
拖拽目標
一個設定draggable
屬性的值為true
DOM元素或者一個選中狀態的文字區塊可以成為拖拽目標。
<div draggable="true"></div>
OR
放置目標
一個綁定了下圖放置目標對應的5個事件的DOM元素可以成為放置目標。
事件
拖放API有8個事件,其中有3個事件繫結在拖拽目標上,有5個事件繫結在放置目標上。
繫結在拖拽目標
Evnet | Description |
---|---|
dragstart | 當用戶開始拖拽一個元素或者一個文字選取區塊的時觸發。 |
drag | 當用戶正在拖拽一個元素或者一個文字選取區塊的時觸發。 |
dragend | 當用戶結束拖拽一個元素或者一個文字選取區塊的時觸發。(如放開滑鼠按鍵或按下鍵盤的 escap 鍵) |
繫結在放置目標
Event | Description |
---|---|
dragenter | 當一個元素或文字選取區塊被拖曳移動進入一個有效的放置目標時觸發。 |
dragover | 當一個元素或文字選取區塊被拖曳移動經過一個有效的放置目標時觸發。 |
dragleave | 當一個元素或文字選取區塊被拖曳移動離開一個有效的放置目標時觸發。 |
dragexist | 當一個元素不再是被選取中的拖曳元素時觸發。(Firefox能觸發,觸發順序:dragexist->dragleave->drop;Chrome無法觸發) |
drop | 當一個元素或文字選取區塊被放置至一個有效的放置目標時觸發。 |
通過下圖能更直觀觀察每個事件觸發的時機
注意:在dragover事件中使用
event.preventDefault();
阻止預設事件,才能觸發drop事件
DataTransfer物件
在進行拖放操作時,會觸發上面所述的8個事件,每個event事件物件中都會有DataTransfer物件用來儲存被拖動的資料。它可以儲存一項或多項資料、一種或者多種資料型別。
effectAllowed
用來指定拖動時被允許的效果。
在dragstart事件中設定
屬性
dropEffect
設定實際的放置效果,它應該始終設定成effectAllowed
在dragenter事件和dragover事件中設定
effectAllowed和dropEffect屬性的栗子:戳我看原始碼
files
包含一個在資料傳輸上所有可用的本地檔案列表。如果拖動操作不涉及拖動檔案,此屬性是一個空列表。
filesZoneEl.addEventListener("drop",(event) => {
event.preventDefault();
let files = event.dataTransfer.files;
for (let i = 0,len = files.length; i < len; i++) {
let liEl = document.createElement("li");
liEl.innerHTML = files[i].name;
filesListEl.appendChild(liEl);
}
});
types
儲存一個被儲存資料的型別列表作為第一項,順序與被新增資料的順序一致。如果沒有新增資料將返回一個空列表。
items
儲存DataTransferItem資料物件的列表。
方法
addElement()
設定拖動源。
event.dataTransfer.addElement(element);
setData()
為一個給定的型別設定資料並存儲在items屬性中。
getData()
從items屬性中獲取給定型別的資料,無資料時返回空字串。
event.dataTransfer.getData(type);
clearData()
從items屬性中刪除與給定型別關聯的資料,若型別為空則刪除所有資料。
event.dataTransfer.clearData(type);
setDragImage()
自定義一個期望的拖動時的圖片,預設為被拖動的節點。
event.dataTransfer.setDragImage(imgElement,offsetX,offsetY);
Param | Description |
---|---|
imgElement | 要用作拖動反饋影象元素。 |
offsetX | 影象內的水平偏移量。 |
offsetY | 影象內的垂直偏移量。 |
設定拖動時的圖片時,要把圖片預載入,否則圖片會在拖動開始dragstart事件觸發時才會載入圖片,會導致拖動圖出不來或閃一下的後果。可把圖片放到<img>
標籤並設定display:none;
,原理詳看我之前的文章Web圖片資源的載入與渲染時機。
DataTransferItemList
dataTramsfer物件的items屬性,包含了一系列DataTransferItem拖拽資料物件。
屬性
length
陣列長度。
方法
add()
增加一個拖拽資料物件到items屬性中,並返回增加的拖拽資料物件。
event.dataTransfer.items.add(file);
remove()
從items屬性中移除指定位置的一個拖拽資料物件。
event.dataTransfer.items.remove(index);
clear()
清空items屬性中的所拖拽資料物件。
event.dataTransfer.items.clear();
DataTransferItem
DataTransferItemList列表中的拖拽資料物件。
屬性
kind
拖拽資料物件型別。
Value | Description |
---|---|
file | 檔案型別。 |
string | 文字字串型別。 |
type
MIME型別的Unicode字串,例如text/plain、text/html或image/png。
方法
getAsFile()
若拖拽資料物件是檔案型別,則返回一個檔案物件。
let itemList = event.dataTransfer.items;
for (let i = 0,len = itemList.length; i < len; i++) {
if (itemList[i].kind == "file") {
console.log(itemList[i].getAsFile());
}
}
getAsString()
若拖拽資料物件是文字字串型別,通過回撥函式獲取拖拽資料中的字串資料。
let itemList = event.dataTransfer.items;
for (let i = 0,len = itemList.length; i < len; i++) {
if (itemList[i].kind == "string") {
itemList[i].getAsString((data) => {
console.log(data);
});
}
}
拖放物件的資料儲存
在進行拖放操作時,有可能需要把拖拽目標的資料傳送給放置目標,此時一般操作是在dragstart事件觸發時把需要的資料儲存到一個變數,然後再drop事件觸發時獲取這個變數。但當dragstart事件和drop事件在不同的檔案定義,又不想玷汙全域性變數的情況下,我們需要更好的辦法來儲存拖放資料。
在DataTransfer物件中的items屬性就是用來儲存拖放資料的,資料型別分為文字型別和檔案型別。
儲存文字字串型別資料:
event.dataTransfer.setData(type,data);
OR
event.dataTransfer.items.add(data,type);
一種文字字串型別只能儲存一個數據,當重複文字字串型別儲存資料時,後者會覆蓋前者。
儲存檔案型別資料:
event.dataTransfer.items.add(file);
獲取所有文字字串型別的拖拽資料物件
event.dataTransfer.types
獲取所有檔案型別的拖拽資料物件
let files = event.dataTransfer.files;
for (let i = 0,len = files.length; i < len; i++) {
console.log(files[i]);
}
OR
let itemList = event.dataTransfer.items;
for (let i = 0,len = itemList.length; i < len; i++) {
if (itemList[i].kind == "file") {
console.log(itemList[i].getAsFile());
}
}
獲取所有文字字串型別的拖拽資料物件
let itemList = event.dataTransfer.items;
for (let i = 0,len = itemList.length; i < len; i++) {
if (itemList[i].kind == "string") {
itemList[i].getAsString((data) => {
console.log(data);
});
}
}
獲取指定文字字串型別的拖拽資料物件
event.dataTransfer.getData(type);
刪除指定文字字串型別的拖拽資料物件
event.dataTransfer.clearData(type);
刪除指定位置的拖拽資料物件
event.dataTransfer.items.remove(index);
清空所有拖拽資料物件
event.dataTransfer.clearData();
OR
event.dataTransfer.items.clear();
栗子
上面的幾個栗子都使用了以上方法儲存和獲取拖拽資料物件,感興趣的可以看看原始碼。
歡迎關注:Leechikit
原文連結:segmentfault.com到此本文結束,歡迎提問和指正。
寫原創文章不易,若本文對你有幫助,請點贊、推薦和關注作者支援。
本文轉載於:猿2048https://www.mk2048.com/blog/blog.php?id=h1kcba0khcb