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>
詳しくは、以下の記事を参照してください。
ドラッグするデータの定義
アプリケーションは、ドラッグ操作にいくつでもデータ項目を含めることが自由にできます。各データ項目は特定の 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 通りの効果が発生する可能性があります。
copyはドラッグしたデータが現在の場所からドロップされる場所にコピーされることを示します。moveはドラッグデータが現在の場所からドロップされる場所に移動されることを示します。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
DataTransferinterface - Copying and moving elements with the
DataTransferListIteminterface - ファイルのドラッグ & ドロップ (Firefox のみ): http://jsfiddle.net/9C2EF/
- ファイルのドラッグ & ドロップ (全ブラウザー): https://jsbin.com/hiqasek/
- Drag and Drop API を使った駐車場プロジェクト: https://park.glitch.me/ (ここで編集できます)
仕様書
| Specification |
|---|
| HTML Standard # dnd |