デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI
ドラッグ&ドロップAPIは、名前のとおり、ページ上のさまざまな要素をマウスでドラッグ&ドロップできるようにするための仕組みです。
一例を挙げると、ドラッグ&ドロップ機能とFile APIとを組み合わせることで、ブラウザに対してドロップしたファイルをそのままサーバーにアップロードできるようになるなど、よりデスクトップアプリ的な仕掛けを実装できるようになります。
- TIPS 059:特定の要素をドラッグ可能にする
- TIPS 060:要素をドロップ可能にする
- TIPS 061:ドラッグ&ドロップ時のスタイルを設定する
- TIPS 062:他のアプリからテキストデータを受け取る
- TIPS 063:ファイルをドラッグ&ドロップする
- TIPS 064:ドラッグ&ドロップで許可される動作を指定する
- TIPS 065:ドラッグアイコンをカスタマイズする
仕掛けそのものは単純ですが、アプリの操作性を大きく変える可能性を持ったAPIと言えるでしょう。ドラッグ&ドロップAPIのブラウザごとの対応バージョンは、以下のとおりです。
表1:ドラッグ&ドロップAPIの対応状況
ブラウザ | 対応バージョン |
---|---|
Internet Explorer | 5.5以降(*) |
Firefox | 3.5以降 |
Chrome | 4以降 |
Safari | 5以降 |
Opera | 12以降 |
*:draggable属性は10以降
サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。
TIPS 059:特定の要素をドラッグ可能にする
ドラッグ&ドロップ機能を利用するには、まず「その要素がドラッグ可能である」ことを宣言しておく必要があります。ページ内の特定の要素をドラッグできるようにするには、対象の要素にグローバル属性であるdraggable属性を付与します。
[リスト01]、要素をドラッグ可能に(dnd.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HTML5 TIPS</title>
...中略...
</head>
<body>
<div id="d1" draggable="true">こんにちは、赤ちゃん!</div>
<img id="d2" src="wings.jpg" />
</body>
</html>
draggable属性には、true(ドラッグ可能)、false(ドラッグ不可)を指定してください。ただし、以下の要素については、デフォルトでドラッグ可能ですので、draggable属性を明示する必要はありません。
- src属性が指定されている要素
- href属性が指定されている要素
- 選択されたテキスト
確かに、サンプルでも要素にはdraggable属性を付与していないことが確認できます。逆に、これらの要素をドラッグ不可にする場合には、明示的にdraggable属性をfalseにセットしなければなりません。
TIPS 060:要素をドロップ可能にする
要素をドラッグできるようにしただけでは、ほとんど意味がありません。一般的には、ドラッグした要素をどこかにドロップできるような仕組みを設ける必要があります。
例えば以下のサンプルは、画像をドラッグしてあらかじめ決められた領域にドロップし、移動させるための仕組みです。
[リスト02]画像をドラッグ&ドロップで移動するコード(drop.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HTML5 TIPS</title>
<script>
window.addEventListener('DOMContentLoaded', function() {
// ドラッグ対象要素、ドロップ先要素を取得
var drag = document.querySelector('#drag');
var drop = document.querySelector('#drop');
// ドラッグ開始時に、ドラッグする要素のid値をセット(1)
drag.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('text', e.target.id);
}, true);
// dragoverイベントをキャンセル(3)
drop.addEventListener('dragover', function(e) {
e.preventDefault();
}, true);
// ドロップ時に、ドラッグ要素をドロップ領域に追加(移動(2))
drop.addEventListener('drop', function(e) {
var id = e.dataTransfer.getData('text');
e.currentTarget.appendChild(document.getElementById(id));
e.preventDefault();
}, true);
});
</script>
</head>
<body>
<!--ドラッグ可能な画像-->
<div style="width:250px; height:70px;">
<img id="drag" src="wings.jpg" draggable="true" />
</div>
<!--ドロップ先の領域-->
<div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div>
</body>
</html>
ドラッグ&ドロップに関するイベントとしては、以下のようなものが用意されています。
表2:ドラッグ&ドロップ関連のイベント
分類
イベント
発生タイミング
ドラッグ
dragstart
ドラッグの開始
drag
ドラッグ中
dragend
ドラッグを終了
ドロップ
dragenter
ドラッグ要素がドロップ領域に入った
dragover
ドラッグ要素がドロップ領域にある
dragleave
ドラッグ要素がドロップ領域から出た
drop
ドロップした
最低限、ドラッグ&ドロップ機能を実装するには、この中からdragstart、dragover、dropイベントリスナーを準備する必要があります。dragstartイベントでドラッグ元要素を記録し、dragoverイベントでドラッグ中の処理を、dropイベントでドロップ時の操作を、それぞれ受け持つわけです。
そして、これらのイベントリスナーで中心となるのは、DataTransferオブジェクトです。イベントオブジェクトのdataTransferプロパティ経由でアクセスできます。DataTransferオブジェクトは、ドラッグ&ドロップ時にやりとりするデータを管理するオブジェクトで、以下のようなメンバーを公開しています。
表3:DataTransferオブジェクトの主なメンバー
メンバー
概要
setData(key, value)
ドラッグ&ドロップで受け渡しする情報をキー/値の組み合わせで設定
getData(key)
メソッドで設定されたデータを、指定のキーで取得
clearData()
メソッドで設定されたデータをクリア
setDragImage(img, x, y)
ドラッグアイコンを指定(x、yでポインタからの相対位置を指定)
files
他のアプリからドラッグされたファイルを取得
effectAllowed
ドラッグ要素で許可される操作
dropEffect
ドロップ領域で許可される操作
まず、(1)のdragstartイベントリスナーでは、ドラッグした要素のid値を保存しておきます。この値を(2)のdropイベントリスナーで取り出し、これをキーにドラッグ元要素を操作しています(ここではドラッグ元要素をドラッグ領域の子要素として追加します)。引数keyには、テキスト情報の場合は「text」を、URL/ファイルリストの場合には「url」のいずれかを指定します。
(3)のdragoverイベントリスナーでpreventDefaultメソッドを呼び出しているのは、デフォルトの動作ではブラウザ標準の挙動が優先されてしまい、ドロップ操作が拒否されてしまうからです。そのため、ここで明示的にブラウザの挙動をキャンセルしておきます。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>HTML5 TIPS</title> ...中略... </head> <body> <div id="d1" draggable="true">こんにちは、赤ちゃん!</div> <img id="d2" src="wings.jpg" /> </body> </html>
draggable属性には、true(ドラッグ可能)、false(ドラッグ不可)を指定してください。ただし、以下の要素については、デフォルトでドラッグ可能ですので、draggable属性を明示する必要はありません。
- src属性が指定されている要素
- href属性が指定されている要素
- 選択されたテキスト
確かに、サンプルでも要素にはdraggable属性を付与していないことが確認できます。逆に、これらの要素をドラッグ不可にする場合には、明示的にdraggable属性をfalseにセットしなければなりません。
TIPS 060:要素をドロップ可能にする
要素をドラッグできるようにしただけでは、ほとんど意味がありません。一般的には、ドラッグした要素をどこかにドロップできるような仕組みを設ける必要があります。
例えば以下のサンプルは、画像をドラッグしてあらかじめ決められた領域にドロップし、移動させるための仕組みです。
[リスト02]画像をドラッグ&ドロップで移動するコード(drop.html)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>HTML5 TIPS</title> <script> window.addEventListener('DOMContentLoaded', function() { // ドラッグ対象要素、ドロップ先要素を取得 var drag = document.querySelector('#drag'); var drop = document.querySelector('#drop'); // ドラッグ開始時に、ドラッグする要素のid値をセット(1) drag.addEventListener('dragstart', function(e) { e.dataTransfer.setData('text', e.target.id); }, true); // dragoverイベントをキャンセル(3) drop.addEventListener('dragover', function(e) { e.preventDefault(); }, true); // ドロップ時に、ドラッグ要素をドロップ領域に追加(移動(2)) drop.addEventListener('drop', function(e) { var id = e.dataTransfer.getData('text'); e.currentTarget.appendChild(document.getElementById(id)); e.preventDefault(); }, true); }); </script> </head> <body> <!--ドラッグ可能な画像--> <div style="width:250px; height:70px;"> <img id="drag" src="wings.jpg" draggable="true" /> </div> <!--ドロップ先の領域--> <div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div> </body> </html>
ドラッグ&ドロップに関するイベントとしては、以下のようなものが用意されています。
表2:ドラッグ&ドロップ関連のイベント
分類 | イベント | 発生タイミング |
---|---|---|
ドラッグ | dragstart | ドラッグの開始 |
drag | ドラッグ中 | |
dragend | ドラッグを終了 | |
ドロップ | dragenter | ドラッグ要素がドロップ領域に入った |
dragover | ドラッグ要素がドロップ領域にある | |
dragleave | ドラッグ要素がドロップ領域から出た | |
drop | ドロップした |
最低限、ドラッグ&ドロップ機能を実装するには、この中からdragstart、dragover、dropイベントリスナーを準備する必要があります。dragstartイベントでドラッグ元要素を記録し、dragoverイベントでドラッグ中の処理を、dropイベントでドロップ時の操作を、それぞれ受け持つわけです。
そして、これらのイベントリスナーで中心となるのは、DataTransferオブジェクトです。イベントオブジェクトのdataTransferプロパティ経由でアクセスできます。DataTransferオブジェクトは、ドラッグ&ドロップ時にやりとりするデータを管理するオブジェクトで、以下のようなメンバーを公開しています。
表3:DataTransferオブジェクトの主なメンバー
メンバー | 概要 |
---|---|
setData(key, value) | ドラッグ&ドロップで受け渡しする情報をキー/値の組み合わせで設定 |
getData(key) | メソッドで設定されたデータを、指定のキーで取得 |
clearData() | メソッドで設定されたデータをクリア |
setDragImage(img, x, y) | ドラッグアイコンを指定(x、yでポインタからの相対位置を指定) |
files | 他のアプリからドラッグされたファイルを取得 |
effectAllowed | ドラッグ要素で許可される操作 |
dropEffect | ドロップ領域で許可される操作 |
まず、(1)のdragstartイベントリスナーでは、ドラッグした要素のid値を保存しておきます。この値を(2)のdropイベントリスナーで取り出し、これをキーにドラッグ元要素を操作しています(ここではドラッグ元要素をドラッグ領域の子要素として追加します)。引数keyには、テキスト情報の場合は「text」を、URL/ファイルリストの場合には「url」のいずれかを指定します。
(3)のdragoverイベントリスナーでpreventDefaultメソッドを呼び出しているのは、デフォルトの動作ではブラウザ標準の挙動が優先されてしまい、ドロップ操作が拒否されてしまうからです。そのため、ここで明示的にブラウザの挙動をキャンセルしておきます。
デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- HTML5のドラッグ&ドロップAPI、File API、Web Storage
- JavaScriptでローカルファイルを自在に操る- File API
- プラグインは要らない!音声/動画対応したHTML5- / 要素
- スマホアプリ開発にも便利な位置情報API- Geolocation API-
- クッキーより便利になったブラウザ標準ストレージ- Web Storage
- HTML+JavaScriptだけでブラウザに図形描画- Canvas API-
- サンプルのプログラムコード解説
- HTML+JavaScriptだけでブラウザに図形描画(3)- Canvas API-
- HTML+JavaScriptだけでブラウザに図形描画(2)- Canvas API-
- 「TAURI」で「丸アートお絵描き」アプリを作ろう