HTML ドラッグ & ドロップ API
====================

**HTML ドラッグ & ドロップ**インターフェイスにより、アプリケーションはブラウザーでドラッグ & ドロップ機能を使用することができます。

ユーザーはマウスで*ドラッグ可能*な要素を選択し、その要素を*ドロップ可能*な要素へドラッグし、マウスボタンを離すことでドロップすることができます。ドラッグ操作の間、*ドラッグ可能な*要素の半透明の表示がマウスポインターに続きます。

*ドラッグ可能*にできる要素の種類、*ドラッグ可能な*要素が生成するフィードバックの種類、および*ドロップ可能な*要素はカスタマイズできます。

この HTML ドラッグ & ドロップの概要では、インターフェイスの説明、アプリケーションにドラッグ & ドロップのサポートを追加するための基本的なステップ、およびインターフェイスの相互運用性の要約があります。

ドラッグイベント
--------

HTML ドラッグ & ドロップ では DOM イベントモデル と マウスイベント を継承した *ドラッグイベント* を使います。典型的な*ドラッグ操作*は、ユーザーが*ドラッグ可能な*要素を選択したときに始まり、ユーザーが*ドロップ可能な*要素に要素をドラッグしたときに継続し、ユーザーがドラッグ可能な要素を離したときに終わります。

ドラッグ操作のあいだ、いくつかのイベント種類が発生し、そのうちいくつかは `drag` や `dragover` イベントのように、複数発生することもあります。

それぞれのドラッグイベントの種類には、関連したイベントハンドラーがあります。

| イベント | 発生する条件… |
| --- | --- |
| `drag` | …ドラッグ項目（要素や選択テキスト）がドラッグされた場合 |
| `dragend` | …ドラッグ操作の終了（マウスボタンを離したり、Esc キーを押したりした場合。詳しくはドラッグの終了を参照。） |
| `dragenter` | …ドラッグ項目が有効なドロップ対象に入った場合（ドラッグターゲットの特定を参照） |
| `dragleave` | …ドラッグ項目が有効なドロップ対象を離れた場合 |
| `dragover` | …ドラッグ項目が有効なドロップ対象にドラッグされた場合、数百ミリ秒ごとに |
| `dragstart` | …ユーザーが項目をドラッグ開始した場合（ドラッグ操作の開始 を参照） |
| `drop` | …項目が有効なドロップ対象にドロップされた場合（ドロップの実行 を参照） |

**メモ:** `dragstart` と `dragend` イベントは、どちらも OS からブラウザーにファイルをドラッグしたときには発生しません。

インターフェイス
--------

HTML ドラッグ & ドロップのインターフェイスは `DragEvent`、`DataTransfer`、`DataTransferItem`、`DataTransferItemList` です。

`DragEvent` インターフェイスには、コンストラクターと `dataTransfer` プロパティ一つがあり、これは `DataTransfer` オブジェクトです。

`DataTransfer` オブジェクトはドラッグイベントの状態、例えば (`copy` や `move` のような) ドラッグの種類や、ドラッグのデータ (1 つ以上の項目)や、各*ドラッグ項目*の MIME タイプのようなものを含んでいます。`DataTransfer` オブジェクトにはドラッグデータを追加・削除するメソッドもあります。

`DragEvent` と `DataTransfer` インターフェイスは、アプリケーションに HTML ドラッグ & ドロップ機能を追加するために必要な唯一のものです。 (Firefox では Gecko 独自拡張を `DataTransfer` オブジェクトへ施していますが、この拡張機能は Firefox でのみ動作します。)

それぞれの `DataTransfer` オブジェクトには `items` プロパティがあり、これは `DataTransferItem` オブジェクトの `list` です。 `DataTransferItem` オブジェクトは単一の*ドラッグ項目*を表し、それぞれが `kind` プロパティ (`string` か `file` の値を取る) と項目の MIME タイプを表す `type` プロパティを持ちます。`DataTransferItem` オブジェクトにはドラッグ項目のデータを取得するメソッドもあります。

`DataTransferItemList` オブジェクトは `DataTransferItem` オブジェクトのリストです。このリストオブジェクトはリストにドラッグ項目を追加したり、リストからドラッグ項目を削除したり、ドラッグ項目のリストをクリアするメソッドを持ちます。

`DataTransfer` と`DataTransferItem` インターフェイスの主な違いは、前者が同期の `getData()` メソッドを使ってドラッグ項目のデータにアクセスするのに対し、後者は代わりに非同期の`getAsString()` メソッドを使うことです。.

**メモ:** `DragEvent` と `DataTransfer` はデスクトップブラウザーでは広く対応していますが、 `DataTransferItem` と `DataTransferItemList` インターフェイスのブラウザーの対応は限られています。相互運用性について、より詳しくは相互運用性を見てください。

基本
--

この節は、アプリにドラッグ & ドロップ機能を追加する基本手順のまとめです。

### ドラッグ可能なものを特定

要素を*ドラッグ可能*とするには、以下のコードのように `draggable` 属性と `ondragstart` のイベントハンドラーを追加することが求められます。


```html
<script>
 function dragstart\_handler(ev) {
 // Add the target element's id to the data transfer object
 ev.dataTransfer.setData("text/plain", ev.target.id);
 }

 window.addEventListener("DOMContentLoaded", () => {
 // Get the element by id
 const element = document.getElementById("p1");
 // Add the ondragstart event listener
 element.addEventListener("dragstart", dragstart\_handler);
 });
</script>

<p id="p1" draggable="true">この要素はドラッグできます。</p>
```


詳しくは、以下の記事を参照してください。

* draggable 属性リファレンス
* ドラッグ操作ガイド
### ドラッグするデータの定義

アプリケーションは、ドラッグ操作にいくつでもデータ項目を含めることが自由にできます。各データ項目は特定の `type` の文字列、よくあるのは `text/html` のような MIME タイプです。

各`ドラッグイベント`はイベントのデータを格納する`dataTransfer` プロパティを持ちます。このプロパティ (これは `DataTransfer` オブジェクトです) にはドラッグデータを管理するメソッドもあります。`setData()` メソッドはドラッグデータに項目を追加するのに使用され、その例は下記の通りです。


```js
function dragstart\_handler(ev) {
  // 異なる種類のドラッグデータを追加する
  ev.dataTransfer.setData("text/plain", ev.target.innerText);
  ev.dataTransfer.setData("text/html", ev.target.outerHTML);
  ev.dataTransfer.setData(
    "text/uri-list",
    ev.target.ownerDocument.location.href,
  );
}
```


* ドラッグ & ドロップで使用される一般的なデータ型の一覧 (テキスト、HTML、リンク、ファイルなど) については、推奨されるドラッグ型をご覧ください。
* ドラッグデータについて詳しくは、ドラッグデータをご覧ください。
### ドラッグ画像の定義

既定では、ブラウザーはドラッグ操作中にポインターの横に現れる画像を提供します。しかし以下の例のように、アプリケーションは `setDragImage()` メソッドでカスタム画像を定義できます。


```js
function dragstart\_handler(ev) {
  // 画像を作成し、ドラッグ画像として使う。
  // 注: "example.gif" は実際の画像の URL に変更してください。
  // でないと、既定ののドラッグ画像が使用されます。
  let img = new Image();
  img.src = "example.gif";
  ev.dataTransfer.setDragImage(img, 10, 10);
}
```


ドラッグフィードバック画像について詳しくは、下記を参照してください。

* ドラッグフィードバック画像の設定
### ドラッグ効果の定義

`dropEffect` プロパティはドラッグ & ドロップ操作中のユーザーへのフィードバックを管理するのに使います。よくあるのはドラッグ中にどのカーソルをブラウザーが表示するかに影響します。例えば、ユーザーがドロップターゲット上に持ってきたとき、ブラウザーのカーソルは起こる動作の種類を示すことがあります。

3 通りの効果が発生する可能性があります。

1. **`copy`** はドラッグしたデータが現在の場所からドロップされる場所にコピーされることを示します。
2. **`move`** はドラッグデータが現在の場所からドロップされる場所に移動されることを示します。
3. **`link`** はドラッグデータが元からドロップ先にある種の関連や接続が作成されることを示します。

ドラッグ操作の間、ある効果はある場所にだけ許可されることを示すために、ドラッグ効果は変更される場合があります。

下記の例はこのプロパティの使い方を示します。


```js
function dragstart\_handler(ev) {
  ev.dataTransfer.dropEffect = "copy";
}
```


詳しくは以下を参照してください。

* ドラッグの効果
### ドロップゾーンの定義

既定では、ブラウザーはほとんどの HTML 要素に何かがドロップされたとき、あらゆることが発生するのを防いでいます。この動作を変更して要素を*ドロップゾーン*や*ドロップ可能*にするには、要素は `ondragover` と `ondrop` イベントハンドラー属性を持たねばなりません。

以下の例は、この属性の使い方と、各属性の基本的なイベントハンドラーを示しています。


```html
<script>
 function dragover\_handler(ev) {
 ev.preventDefault();
 ev.dataTransfer.dropEffect = "move";
 }
 function drop\_handler(ev) {
 ev.preventDefault();
 // 移動された要素のidを取得して、その要素をtargetのDOMに追加する
 const data = ev.dataTransfer.getData("text/plain");
 ev.target.appendChild(document.getElementById(data));
 }
</script>

<p
 id="target"
 ondrop="drop\_handler(event)"
 ondragover="dragover\_handler(event)">
  Drop Zone
</p>
```


各ハンドラーが `preventDefault()` を呼んで、このイベントが (タッチイベントやポインターイベントなどに) 追加で処理されることを防いでいるのに注意してください

詳しくは、以下を参照してください。

* ドロップ先の指定
### ドロップ効果の扱い

`drop` イベントのハンドラーでは、アプリケーション固有の方法でドラッグデータを自由に処理できます。

ふつう、アプリケーションは`getData()` メソッドでドラッグ項目を取得して、そのようよ処理します。加えて、アプリケーションのセマンティクスは `dropEffect` の値や修飾キーの状態により異なります。

下記の例では、ドラッグデータからソース要素の `id` を取得し、 `id` を使ってソース要素をドロップ要素に移動するドロップハンドラーを示しています。


```html
<script>
 function dragstart\_handler(ev) {
 // 対象となる要素の id を DataTransfer オブジェクトに追加する
 ev.dataTransfer.setData("application/my-app", ev.target.id);
 ev.dataTransfer.effectAllowed = "move";
 }
 function dragover\_handler(ev) {
 ev.preventDefault();
 ev.dataTransfer.dropEffect = "move";
 }
 function drop\_handler(ev) {
 ev.preventDefault();
 // 移動された要素の id を取得して、その要素を target の DOM に追加する
 const data = ev.dataTransfer.getData("application/my-app");
 ev.target.appendChild(document.getElementById(data));
 }
</script>

<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>
```


詳しくは、以下を参照してください。

* ドロップの実行
### ドラッグの終了

ドラッグ操作の終わりに、 `dragend` イベントが*ドラッグ元の*要素で発生します。 — ドラッグが開始された対象の要素です。

このイベントはドラッグの完了とキャンセルのどちらでも発生します。 `dragend` イベントハンドラーは `dropEffect` プロパティの値をチェックしてドラッグ操作が成功したか否かを決定できます。

ドラッグ操作の終了を扱うことの詳細は、以下を参照してください。

* ドラッグの終了
相互運用性
-----

DataTransferItem インターフェイスのブラウザー互換性テーブルに見られるように、ドラッグ & ドロップの相互接続性はデスクトップブラウザーでは相対的に広いです（対応の少ない `DataTransferItem` と `DataTransferItemList` インターフェイスを除いて）。このデータはモバイルブラウザーでのドラッグ & ドロップの対応はとても低いことも示しています。

例とデモ
----

* Copying and moving elements with the `DataTransfer` interface
* Copying and moving elements with the `DataTransferListItem` interface
* ファイルのドラッグ & ドロップ (Firefox のみ): http://jsfiddle.net/9C2EF/
* ファイルのドラッグ & ドロップ (全ブラウザー): https://jsbin.com/hiqasek/
* Drag and Drop API を使った駐車場プロジェクト: https://park.glitch.me/ (ここで編集できます)
仕様書
---

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

関連情報
----

* ドラッグ操作
* 推奨されるドラッグ型
* HTML Living Standard: Drag and Drop
* Drag and Drop interoperability data from CanIUse