了解如何使用 Drag and Drop API 為您的使用者創建交互式體驗
使用 Drag and Drop API,您可以定義頁面中的哪些元素是可拖動的,並在用戶拖動元素時攔截它。
它在現代瀏覽器中得到了很好的支持:
在我們開始研究這個 API 之前,我們必須知道如何定義頁面中的可拖動元素。我們可以通過在頁面的 HTML 中添加 draggable
屬性並將其設置為 true
來實現:
<div draggable="true">
...
</div>
這就足以使元素成為可拖動的。
提示:圖片、文字選擇和鏈接默認情況下是可拖動的,除非您在它們上面設置了
draggable
為 false。
我們還可以從用戶計算機中將文件拖動到瀏覽器中。在這種情況下,我們傳輸的是文件。
我們還需要澄清的另一點是元素可以拖放到哪裡。就像我們不能隨意拖動任何元素一樣,我們也不能隨意拖放到任何元素中。元素必須是有效的放置目標。
要使元素成為放置目標,您需要侦聽其 dragover
事件,並根據需要從該事件返回 false 或調用 preventDefault()
:
const element = document.querySelector('#my-drop-target')
element.addEventListener('dragover', event => {
event.preventDefault()
})
一旦完成了上述步驟,我們就擁有了一個可拖動元素和一个放置目標,就可以開始進一步操作了。我們可以與可拖動元素交互的事件有:
dragstart
drag
dragend
放置目標上可以交互的事件有:
dragenter
dragover
dragleave
drop
拖放操作概述及觸發的事件
當用戶開始拖動一個可拖動元素時,可以進行鼠標點擊並移動鼠標,或者也可以單擊並保持選擇,然後移動選擇區,此時會在元素上觸發 dragstart
事件:
element.addEventListener('dragstart', event => {
//...
})
傳遞給事件處理函數的 event
對象是一個 DragEvent
對象。它是從更一般的事件對象中擴展出來的,與所有其他事件(鼠標,鍵盤,滾動等)共享。
此時,元素正在被拖動,並且正在觸發 drag
事件。當元素被拖動時,該事件會被觸發多次,因此我們必須像 scroll
或 mouseover
事件一樣使用延遲。
一旦進入一個放置目標:
- 會在放置目標上觸發
dragenter
事件 - 會在放置目標上觸發
dragover
事件
如果一個被拖動的元素首先進入一個放置目標,然後又移出該目標,則會在放置目標上觸發 dragleave
事件。
如果用戶釋放了滑鼠按鈕,則會在正在拖動的元素上觸發 dragend
事件,並且在放置目標上觸發 drop
事件。
拖曳數據:DataTransfer
與拖放相關的每個事件都是一個DragEvent
對象,正如我之前提到的,它帶有一個名為 dataTransfer
的屬性,該屬性保存正在拖動的數據,並提供五個屬性:
dropEffect
effectAllowed
files
items
(只讀)types
(只讀)
拖曳事件開始時,您可以進行一些操作。
設置/獲取效果
您可以在 dragstart
事件中通過設置 effectAllowed
屬性來設置拖動操作的期望效果。您有一些選項,用於設置放置目標應如何處理放下的元素:
none
:不應該放下move
:可以移動copy
:可以複製link
:可以鏈接copyMove
:可以複製或移動copyLink
:可以複製或鏈接linkMove
:可以移動或鏈接all
:可以複製、移動或鏈接
(全部都是字串)
默認值為 all
。
dropEffect
屬性用於獲取拖放操作的類型,這次是由用戶通過使用修改鍵設置的。例如,在 Mac 上按下 Alt
鍵會將放置目標設置為複製項目而不是移動它。
此屬性不是只讀的。我们可以在 dragenter
或 dragover
事件中編輯它,將其設置為以下字符串之一:
none
:不應該放下move
:可以移動copy
:可以複製link
:可以鏈接
示例:
element.addEventListener('dragenter', event => {
event.dataTrasfer.dropEffect = 'move'
})
正在傳輸的數據
您可以從 dataTransfer.items
屬性中訪問正在傳輸的項目,它是一個類似數組的對象,您可以使用循環迭代並訪問每個 DataTransferItem
對象。
DataTransferItem
有2個只讀屬性:
kind
:正在拖動的項目的種類。返回包含file
或string
的字符串type
:項目的 MIME 類型
它還有2個方法:
getAsFile()
:返回表示正在拖動的數據的File
對象getAsString()
:將項目作為字符串傳遞給回調函數
它們具有相似的名稱,但工作方式非常不同。第一個返回一個 File
對象:
element.addEventListener('dragenter', event => {
for (item of event.dataTrasfer.items) {
const theFile = item.getAsFile()
}
})
第二個將項目作為字符串傳遞給回調函數:
element.addEventListener('dragenter', event => {
for (item of event.dataTrasfer.items) {
item.getAsString(theString => {
console.log(theString)
})
}
})
正在拖動的文件類型存儲在 dataTransfer
對象的 types
屬性中。它是一個包含字符串 string
的數組。如果我們正在拖動一個文件,則相應的類型是一個值為 Files
的字符串。
如果正在傳輸文件,則除了在 dataTransfer.items
中列出外,它們還存儲在 dataTransfer
的 files
屬性中。
此屬性指向一個 FileList
對象,列出了正在拖動的文件。
在 Codepen 上查看此演示:
參見 CodePen 上的拖放示例,作者是 Flavio Copes(@flaviocopes)。