HTML 拖放 API
===========

HTML 拖放介面能讓網頁應用程式於 Firefox 及其他瀏覽器中使用拖放功能。舉例來說，使用者可以利用此功能以滑鼠選擇\*可拖曳（draggable）*元素，拖曳至一個*可放置（droppable）*元素上，並放開滑鼠按鍵來放置此元素。在拖曳操作時，一個半透明的*可拖曳（draggable）\*元素會跟隨著滑鼠游標。

對於網站、擴充套件以及 XUL 應用程式來說，你可以自定義能成為\*可拖曳（draggable）\*的元素類型、\*可拖曳（draggable）*元素產生的回鐀類型，以及*可放置（droppable）\*的元素。

此文件為 HTML 拖放的概述，包含了相關介面的說明、在應用程式中加入拖放支援的基本步驟，以及相關介面使用簡介。

拖曳事件
----

HTML 拖放操作基於 `DOM 事件模型`並且使用繼承自`滑鼠事件` (en-US)的\*`拖曳事件`*介面。一個典型的拖曳操作開始於使用者利用滑鼠選取了一個*可拖曳（draggable）*元素、移動滑鼠至一個*可放置（droppable）\*元素並放開滑鼠按鍵。在操作的過程中，會觸發多種類型的事件，且一些事件類型可能會被觸發多次（如 `drag` (en-US) 及 `dragover` (en-US) 事件類型）。

所有的拖曳事件類型都有相關的通用事件處理器（global event handler）。每一種拖曳事件類型及拖曳通用事件處理器屬性都有說明此事件的參考文件。以下的表格提供了每一種事件的簡要說明，以及參考文件的連結。

| 事件 | 事件處理器屬性 | 說明 |
| --- | --- | --- |
| `drag` (en-US) | `ondrag` (en-US) | 於一個元素或文字選取區塊被拖曳時觸發。 |
| `dragend` (en-US) | `ondragend` (en-US) | 於拖曳操作結束時觸發（如放開滑鼠按鍵或按下鍵盤的 escape 鍵）。（請參考結束拖曳 (en-US)。） |
| `dragenter` (en-US) | `ondragenter` (en-US) | 於一個元素或文字選取區塊被拖曳移動進入一個有效的放置目標時觸發。（請參考指定拖曳目標 (en-US)。） |
| `dragleave` (en-US) | `ondragleave` (en-US) | 於一個元素或文字選取區塊被拖曳移動離開一個有效的放置目標時觸發。 |
| `dragover` (en-US) | `ondragover` (en-US) | 於一個元素或文字選取區塊被拖曳移動經過一個有效的放置目標時觸發（每幾百毫秒觸發一次）。 |
| `dragstart` (en-US) | `ondragstart` (en-US) | 於使用者開始拖曳一個元素或文字選取區塊時觸發。（請參考開始拖曳 (en-US)。） |
| `drop` (en-US) | `ondrop` (en-US) | 於一個元素或文字選取區塊被放置至一個有效的放置目標時觸發。（請參考執行放置 (en-US)。） |

注意：`dragstart` 與 `dragend` 事件，在把檔案從作業系統拖放到瀏覽器時，並不會觸發。

介面
--

HTML 拖放介面有 `DragEvent`、`DataTransfer` (en-US)、`DataTransferItem` (en-US) 以及 `DataTransferItemList` (en-US)。

`DragEvent` 介面擁有一個建構式及一個屬性－`dataTransfer` 屬性為一個 `DataTransfer` (en-US) 物件。`DataTransfer` (en-US) 物件包含了拖放事件的狀態，如正在進行的拖放事件類型（例如 `copy` 或 `move`）、拖放中的資料（一或多個項目）以及每一個\*拖放項目（drag item）\*的檔案類型（MIME type）。`DataTransfer` (en-US) 物件也擁有加入及移除拖放資料項目的方法。`DragEvent` 與 `DataTransfer` (en-US) 介面應該是唯一須要加至應用程式中的 HTML 拖放功能。另外，請留意 Firefox 支援了一些 Gecko-specific 擴充予 `DataTransfer` (en-US) 物件使用，雖然這些擴充只能在 Firefox 上作用。

每個 `DataTransfer` (en-US) 物件都包含了 `items` (en-US) 屬性。此屬性乃 `DataTransferItem` (en-US) 物件的 `list` (en-US)。而每個 `DataTransferItem` (en-US) 物件，則代表著一個*拖放單元*，每個拖放單元則擁有代表該資料*種類*的 `kind` (en-US) 屬性（`string` 或 `file`）、還有表示該單元檔案類型（如 MIME）的`type` (en-US) 屬性。另外，`DataTransferItem` (en-US) 物件能取得拖放單元的資料。

`DataTransferItemList` (en-US) 物件為 `DataTransferItem` (en-US) 的列表。該物件列表擁有以下方法：給列表增加拖放單元、從列表刪除拖放單元、還有清除列表內所有的拖放單元。

`DataTransfer` (en-US) 與 `DataTransferItem` (en-US) 介面的最大不同，就是前者使用同步的 `getData()` (en-US) 方法訪問拖放單元的資料；後者則使用非同步的 `getAsString()` (en-US) 方法訪問。

注意：`DragEvent` 與 `DataTransfer` (en-US) 介面受廣泛的桌面瀏覽器支援。但只有少數瀏覽器支援 `DataTransferItem` (en-US) 與 `DataTransferItemList` (en-US) 介面。請參見 Interoperability 以取得有關拖放功能互通性的資訊。

### Gecko-specific interfaces

Mozilla and Firefox support some features not in the standard drag and drop model. These are *convenience functions* to facilitate dragging multiple items and dragging non-string data (such as files). For more information, see Dragging and Dropping Multiple Items. Additionally, see the `DataTransfer` (en-US) reference page for all of the Gecko-specific properties (en-US) and Gecko-specific methods (en-US).

基本用法
----

This section provides a summary of the basic steps to add drag and drop functionality to an application. Each section includes a description of the step, a short code example, and links to additional information.

### Identify what is *draggable*

To make an element *draggable* requires adding the `draggable` (en-US) attribute plus the `ondragstart` (en-US) global event handler, as shown in the following code sample


```js
function dragstart\_handler(ev) {
  console.log("dragStart");
  // Add the target element's id to the data transfer object
  ev.dataTransfer.setData("text/plain", ev.target.id);
}

<body>
  <p id="p1" draggable="true" ondragstart="dragstart\_handler(event);">
    This element is draggable.
  </p>
</body>;
```


See the draggable attribute reference (en-US) and the Drag operations guide for more information.

### Define the drag's data

The application is free to include any number of data items in a drag operation. Each data item is a `string` of a particular `type`, typically a MIME type such as `text/html`.

Each `drag event` has a `dataTransfer` property that *holds* the event's data. This property (which is a `DataTransfer` (en-US) object) also has methods to *manage* drag data. The `setData()` (en-US) method is used to add an item to the drag data, as shown in the following example.


```js
function dragstart\_handler(ev) {
  // Add the drag data
  ev.dataTransfer.setData("text/plain", ev.target.id);
  ev.dataTransfer.setData("text/html", "<p>Example paragraph</p>");
  ev.dataTransfer.setData("text/uri-list", "http://developer.mozilla.org");
}
```


For a list of common data types used for drag and drop (such as text, HTML, links, and files), see Recommended Drag Types (en-US) and for more information about drag data, see Drag Data.

### Define the drag image

By default, the browser supplies an image that appears beside the mouse pointer during a drag operation. However, an application may define a custom image by using the `setDragImage()` (en-US) method as shown in the following example.


```js
function dragstart\_handler(ev) {
  // Create an image and then use it for the drag image.
  // NOTE: change "example.gif" to an existing image or the image
  // will not be created and the default drag image will be used.
  var img = new Image();
  img.src = "example.gif";
  ev.dataTransfer.setDragImage(img, 10, 10);
}
```


To learn more about drag feedback images, see Setting the Drag Feedback Image (en-US).

### Define the drag *effect*

The `dropEffect` (en-US) property is used to control the feedback (typically visual) the user is given during a drag and drop operation. It affects which cursor the browser displays while dragging. For example, when the user hovers over a target drop element, the browser's cursor may indicate the type of operation that will occur.

Three effects may be defined:

`copy` indicates that the data being dragged will be copied from its present location to the drop location.

`move` indicates that the data being dragged will be moved

`link` indicates that some form of relationship or connection will be created between the source and drop locations.

During the drag operation, the drag effects may be modified to indicate that certain effects are allowed at certain locations. If allowed, a drop may occur at that location.

The following example shows how to use this property.


```js
function dragstart\_handler(ev) {
  // Set the drag effect to copy
  ev.dataTransfer.dropEffect = "copy";
}
```


See Drag Effects for more details.

### Define a *drop zone*

By default, the browser prevents anything from happening when dropping something onto the HTML element. To change that behavior so that an element becomes a *drop zone* or is *droppable*, the element must have both `ondragover` (en-US) and `ondrop` (en-US) event handler attributes. The following example shows how to use those attributes and includes basic event handlers for each attribute.


```js
function dragover\_handler(ev) {
  ev.preventDefault();
  // Set the dropEffect to move
  ev.dataTransfer.dropEffect = "move";
}
function drop\_handler(ev) {
  ev.preventDefault();
  // Get the id of the target and add the moved element to the target's DOM
  var data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
<body>
  <div
    id="target"
    ondrop="drop\_handler(event);"
    ondragover="dragover\_handler(event);">
    Drop Zone
  </div>
</body>;
```


Note each handler calls `preventDefault()` to prevent additional event processing for this prevent (such as touch events or pointer events).

For more information, see Specifying Drop Targets.

### Handle the drop *effect*

The handler for the `drop` (en-US) event is free to process the drag data in an application specific way. Typically, an application will use the `getData()` (en-US) method to retrieve drag items and process them accordingly. Additionally, application semantics may differ depending on the value of the `dropEffect` (en-US) and/or the state of modifier keys.

The following example shows a drop handler getting the source element's id from the drag data and then using the id to move the source element to the drop element.


```js
function dragstart\_handler(ev) {
  // Add the target element's id to the data transfer object
  ev.dataTransfer.setData("text/plain", ev.target.id);
  ev.dropEffect = "move";
}
function dragover\_handler(ev) {
  ev.preventDefault();
  // Set the dropEffect to move
  ev.dataTransfer.dropEffect = "move";
}
function drop\_handler(ev) {
  ev.preventDefault();
  // Get the id of the target and add the moved element to the target's DOM
  var data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
<body>
  <p id="p1" draggable="true" ondragstart="dragstart\_handler(event);">
    This element is draggable.
  </p>
  <div
    id="target"
    ondrop="drop\_handler(event);"
    ondragover="dragover\_handler(event);">
    Drop Zone
  </div>
</body>;
```


For more information, see Performing a Drop.

### Drag end

At the end of a drag operation, the `dragend` (en-US) event fires at the *source* element - the element that was the target of the drag start. This event fires whether the drag completed or was canceled. The `dragend` (en-US) event handler can check the value of the `dropEffect` (en-US) property to determine if the drag operation succeeded or not.

For more information about handling the end of a drag operation, see Finishing a Drag (en-US).

Interoperability
----------------

As can be seen in the DataTransferItem interface's Browser Compatibility table (en-US), drag-and-drop interoperability is relatively broad among desktop browsers (except the `DataTransferItem` (en-US) and `DataTransferItemList` (en-US) interfaces have less support). This data also indicates drag and drop support among mobile browsers is very low.

Examples and demos
------------------

* Copying and moving elements with the `DataTransfer` interface
* Copying and moving elements with the `DataTransferListItem` interface
* Dragging and dropping files; Firefox only: http://jsfiddle.net/9C2EF/
* Dragging and dropping files; All browsers: https://jsbin.com/hiqasek/
* A parking project using the Drag and Drop API: https://park.glitch.me/ (You can edit here)
規範
--

| Specification |
| --- |
| HTML Standard  |

參見
--

* Drag Operations
* Dragging and Dropping Multiple Items
* Recommended Drag Types (en-US)
* HTML5 Living Standard: Drag and Drop
* Drag and Drop interoperability data from CanIUse