HTML5拖拽技術介紹
HTML5 的拖拽實現
前提:draggable
將需要拖放的元素設定為 draggable = 'true'(img 和 a 元素預設為 true)
一、拖放相關事件
1. 被拖動元素: ondragstart、ondrag、ondragend
ondragstart
:使用者開始拖動元素時觸發ondrag
:元素正在拖動時觸發ondragend
:使用者完成元素拖動後觸發
2. 放置目標元素(容器): ondragenter、ondragover、ondragleave、ondrop
dragenter
:當被滑鼠拖動的物件進入其容器範圍內時觸發此事件dragover
:當某被拖動的物件在另一物件容器範圍內拖動時觸發此事件dragleave
:當被滑鼠拖動的物件離開其容器範圍內時觸發此事件drop
:在一個拖動過程中,釋放滑鼠鍵時觸發此事件。- 源物件拖放到目標物件中,目標物件完全接受被拖拽物件時觸發,可理解為在目標物件內鬆手時觸發
注意:對於 dragover
和 drop
,預設地,資料/元素無法被放置到其他元素中。為了實現拖放,我們必須阻止元素的這種預設的處理方式: 呼叫 event.preventDefault();
二、資料的傳遞:dataTransfer
所有拖放事件的引數 DragEvent
中,都提供了一個數據傳輸物件: dataTransfer
,用於在源物件和目標物件之間傳遞資料。
DataTransfer
DataTransfer
物件也有向拖拽資料中新增或刪除專案的方法。
參考連結:MDN : DataTransfer
1. dataTransfer的方法
setData(format, data)
該方法設定拖拽事件中要傳遞的資料,向 dataTransfer 中物件中存入資料。
接受兩個引數:
format
:DOMString,表示要新增到 drag object的拖動資料的型別。例如text/plain、text/html、text/xml、text/uri-list
data
event.dataTransfer.setData('text/plain', 'hello world')
注:如果給定型別的資料不存在,則將其新增到拖動資料儲存的末尾,使得 dataTransfer.types 列表中的最後一個專案將是新型別。
getData(format)
該方法獲得拖拽事件中傳遞的資料,從 dataTransfer
物件中讀取資料
引數 format
為在 setData 方法中指定的資料型別,例如: event.dataTransfer.getData('text/plain')
clearData()
該方法清空 dataTransfer
物件中儲存的資料,引數可選,為資料型別。若為空,則清空所有資料。
setDragImage(element, x, y)
該方法通過 img 元素來設定拖放圖示
element
表示拖拽時滑鼠下面的圖片(通常是 image 元素,也可以說 canvas 元素)
x
、y
分別指示相對於圖片的橫向和縱向偏移量,相對應滑鼠指標。
2. dataTransfer的屬性
files 屬性
返回被拖拽的檔案列表,是一個 FileList 物件,有 length 屬性,可通過下標訪問。
如果拖動操作不涉及拖動檔案,則此屬性為空列表.
dropEffect 屬性
獲取當前選定的拖放操作型別或者設定的為一個新的型別。值必須為 none, copy, link 或 move
。
必須在 dragenter
事件處理函式中設定。
- none 不能把元素拖放至此(除文字框外全部元素的預設值)
- move 移動到目標
- copy 複製到目標
- link 目標開啟拖動元素(拖動元素必須是連結並有 URL)
dropEffect 屬性
提供所有可用的操作型別。必須是 none, copy, copyLink, copyMove, link, linkMove, move, all or uninitialized
之一。
必須在 dragstart
事件處理函式中設定。
- uninitialized 沒有設定任何拖放行為
- none 不能由任何行為
- copy 僅允許 dropEffect 值為 copy
- link 僅允許 dropEffect 值為 link
- move 僅允許 dropEffect 值為 move
- copyLink 允許 dropEffect 值為 copy 和 link
- copyMove 允許 dropEffect 值為 copy 和 move
- linkMove 允許 dropEffect 值為 link 和 move
- all 允許任意 dropEffect
三、示例:HTML 拖拽示例 drag & drop
HTML 程式碼
<div class="drag-item" id="dragitem" draggable="true">被拖動元素</div>
<div class="target-area">
<div class="target" id="t1">目標元素</div>
<div class="target" id="t2">目標元素2</div>
</div>
<div class="status-area">
<div id="info">請拖動</div>
<div id="info2"></div>
</div>
JavaScript 程式碼
let item = document.getElementById('dragitem')
let info = document.getElementById('info')
let info2 = document.getElementById('info2')
let targets = document.getElementsByClassName('target')
item.addEventListener('dragstart', function(ev){
ev.target.style.background = "lightgreen";
ev.target.style.color = "black";
ev.target.style.opacity = 0.5;
info.innerHTML = "開始拖動";
// 設定傳遞資料
ev.dataTransfer.setData('itemid', ev.target.id)
})
item.addEventListener('dragend', function(ev){
ev.target.style.background = "black";
ev.target.style.color = "white";
info.innerHTML = "結束拖動";
ev.target.style.opacity = 1;
info2.innerHTML = "";
})
item.addEventListener('drag', function(ev){
info2.innerHTML = "拖動中";
})
for(let target of targets) {
target.addEventListener('dragover', function(ev) {
//預設地,資料/元素無法被放置到其他元素中。
//為了實現拖放,我們必須阻止元素的這種預設的處理方式
ev.preventDefault();
})
target.addEventListener('dragenter', function(ev) {
ev.target.style.border = "3px dotted red";
})
target.addEventListener('dragleave', function(ev) {
ev.target.style.border = "1px solid black";
})
target.addEventListener('drop', function(ev) {
ev.preventDefault();
let id = ev.dataTransfer.getData('itemid')
ev.target.appendChild(document.getElementById(id))
})
target.addEventListener('dragover', function(ev) {
ev.preventDefault();
ev.target.style.border = "3px dotted red";
})
}