使用 Drag and Drop 給Web應用提升互動體驗
什麼是 Drag and Drop
(拖放)?
簡單來說,HTML5 提供了 Drag and Drop
API,允許使用者用滑鼠選中一個可拖動元素,移動滑鼠拖放到一個可放置到元素的過程。
我相信每個人都或多或少接觸過拖放,比如瀏覽器多標籤頁之間的可拖放排序、手機中的App可以隨便拖放排序等等,Drag and Drop
已經給我們提供了更便捷、更靈活的網路應用體驗。
HTML5 Drag and Drop
DnD
規範定義了基於事件的拖放機制和附加標記,以標記網頁上幾乎所有 draggable
的元素型別,一個典型的 drag
操作是這樣開始的:使用者用滑鼠選中一個可拖動的(draggable)元素,移動滑鼠到一個可放置的(droppable)元素,然後釋放滑鼠。 在操作期間,會觸發一些事件型別,有一些事件型別可能會被多次觸發(比如drag 和 dragover 事件型別)。
總結起來很簡單:
Drag Source(What to drag) => Drop Target(Where to drop)
拖拽事件
所有的拖拽事件都對應一個 global event handler
,Dnd API 一個有8個事件,可以分為繫結在 Drag Source 上3個、繫結在 Drag Target 上5個
Drag Source
Event | Description |
---|---|
dragstart | 當用戶開始拖動一個元素或選中的文字時觸發。 |
drag | 當拖動元素或選中的文字時觸發。 |
dragend | 當拖拽操作結束時觸發 (比如鬆開滑鼠按鍵或敲“Esc”鍵)。 |
Drop Target
Event | Description |
---|---|
dragenter | 當拖動元素或選中的文字到一個可釋放目標時觸發。 |
dragover | 當元素或選中的文字被拖到一個可釋放目標上時觸發(每100毫秒觸發一次)。 |
dragexit | 當元素變得不再是拖動操作的選中目標時觸發。 |
dragleave | 當拖動元素或選中的文字離開一個可釋放目標時觸發。 |
drop | 當元素或選中的文字在可釋放目標上被釋放時觸發。 |
注意點
- 在滑鼠操作拖放期間,有一些事件可能觸發多次,(比如:
drag
和dragover
)。使用時注意防抖或節流 - 在
dragover
事件中使用event.preventDefault()
阻止預設事件行為時,才能正確觸發drop
事件 - 在 Firefox 瀏覽器中觸發 drop 時要使用
event.preventDefault()
阻止預設事件行為,以防止開啟一個新的標籤
資料介面
HTML拖拽的資料介面有三個 DataTransfer
、DataTransferItem
和 DataTransferItemList
。
在進行拖放操作時,DataTransfer
物件用來儲存,通過拖放動作,拖動到瀏覽器的資料。它可以儲存一項或多項資料、一種或者多種資料型別。
DataTransfer 常用屬性
屬性 | 型別 | 描述 |
---|---|---|
dropEffect | String | 獲取 / 設定實際的放置效果,它應該始終設定成 effectAllowed 的可能值之一,copy 、move 、link 、none |
effectAllowed | String | 用來指定拖動時被允許的效果。 |
Files | FileList | 儲存一個被儲存資料的型別列表作為第一項,順序與被新增資料的順序一致。如果沒有新增資料將返回一個空列表。 |
types | DOMStringList | 包含一個在資料傳輸上所有可用的本地檔案列表。如果拖動操作不涉及拖動檔案,此屬性是一個空列表。 |
DataTransfer 常用方法
void clearData([in String type])
String getData(in String type)
void setData(in String type, in String data)
void setDragImage(in nsIDOMElement image, in long x, in long y)
注意點
- 通過定義
MIME
(Multipurpose Internet Mail Exchange)來指定資料傳輸型別,例如:text/plain
功能檢測
想象一下我們想開發一個使用HTML5 DnD API來實現的豐富可互動式的應用。結果因為瀏覽器不支援,是不是很糟糕。對我們是否需要使用降級方案還是有很重要的參考意義的。
下面有兩種常用的方法來幫助我們來檢測。
caniuse
Modernizr
Modernizr 是一個出色的可用於檢測使用者瀏覽器是否支援 HTML5
和 CSS3
功能的庫。
if (Modernizr.draganddrop) {
// Browser supports HTML5 DnD.
} else {
// Fallback to a library solution.
}
複製程式碼
實現拖拽
HTML Attribute
實現拖拽元素只需要在dom標籤上加入 draggable="true"
<div id="drag-source" draggable="true"></div>
複製程式碼
CSS User Interface
user-select
可拖拽元素,建議使用 user-select
,避免使用者在拖拽時選取到內部元素。
[draggable="true"] {
/*
To prevent user selecting inside the drag source
*/
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
複製程式碼
cursor
可拖拽元素,建議使用 cursor
,設定可拖拽元素的滑鼠遊標,提升互動。
[draggable="true"] {
cursor: move;
}
複製程式碼
在 Vue 中使用拖拽
Vue 中使用 dnd 可以直接繫結 event
到元件上。
下面栗子包含的內容:
- 使用Vue實現拖放
- 拖放事件以及事件觸發的時機
- 拖放事件的一些效果處理
- 拖拽系統檔案到瀏覽器
DnD 能做什麼?
- 提升網頁上操作互動體驗
- 提供列表排序功能
- 本機與瀏覽器互動
- HTML5遊戲
推薦一些不錯的DnD庫
- interact.js - JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+)
- Sortable - Sortable — is a JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices.
- draggable - The JavaScript Drag & Drop library your grandparents warned you about.
- Vue.Draggable - Vue component allowing drag-and-drop sorting in sync with View-Model. Based on Sortable.js
- vue-grid-layout - A draggable and resizable grid layout, for Vue.js.
- vue-draggable-resizable - Vue2 Component for draggable and resizable elements.
- react-dnd - Drag and Drop for React
- react-beautiful-dnd - Beautiful and accessible drag and drop for lists with React
- react-grid-layout - A draggable and resizable grid layout with responsive breakpoints, for React.
參考
Mozilla HTML_Drag_and_Drop_API
Working with HTML5 Drag-and-Drop