HTML 5では、ドラッグ&ドロップを直接サポートするためのAPIが整備された。以前はmousedown、mousemove、mouseupを利用してドラッグ&ドロップを実現していたが、ブラウザによるネイティブサポートが実現した事で、他のアプリケーションともデータをやり取りできるようになり、コーディングも簡略化された。
HTML 5でドラッグ&ドロップを実現するための最小限の手順は以下の通りだ。
- ドラッグ対象となる要素に「draggable="true"」という属性値をセットする。これにより、対象の要素がドラッグ可能となる。ちなみに、img要素やa要素(hrefの指定が必要)はデフォルトでドラッグ可能である
- ドラッグ&ドロップ関連のイベントを処理するようコードを記述する。以下のようなイベントが存在する
イベント名 | イベントの通知先 | 説明 |
dragstart | ドラッグ対象の要素 | ドラッグが開始された |
drag | ドラッグ対象の要素 | ドラッグ中 |
dragenter | ドラッグ中にマウスオーバーした要素 | ドラッグ操作が要素の範囲内に入った |
dragover | ドラッグ中にマウスオーバーした要素 | ドラッグ操作が要素の範囲内を通過中 |
dragleave | ドラッグ中にマウスオーバーした要素 | ドラッグ操作が要素の範囲内を出た |
drop | ドロップ先の要素 | ドロップされた |
dragend | ドラッグ対象の要素 | ドラッグが終了した |
では、この手順に則ってドラッグ&ドロップを実現したサンプルを以下に示す。以下のサンプルは、「ドラッグしてね!」と表示されているdiv要素を、その下にあるdiv要素に対してドラッグ&ドロップすることができる。ドラッグされるたびに、下のdiv要素には「Hello」という文字列が追加される。
リスト drag-and-drop1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ドラッグ&ドロップのデモ</title>
<script type="text/javascript">
function init() {
var source = document.getElementById("dragme");
var dest = document.getElementById("text");
// (1) ドラッグ開始
source.addEventListener("dragstart", function(ev) {
// dataTransferオブジェクトに対し、データを追加
var dt = ev.dataTransfer;
dt.setData("text/plain", "Hello");
return true;
}, false);
// (2) ドラッグオーバー
dest.addEventListener("dragover", function(ev) {
// デフォルトの動作(ドロップの拒否)を行わない
ev.preventDefault();
return false;
}, false);
// (3) ドロップ
dest.addEventListener("drop", function(ev) {
// DataTransferオブジェクトからデータを取得
var dt = ev.dataTransfer;
var text = dt.getData("text/plain");
dest.textContent += text;
// イベントのバブリングを停止
ev.stopPropagation();
return false;
}, false);
}
</script>
</head>
<body onload="init()">
<h1>ドラッグ&ドロップのデモ</h1>
<!-- (4) draggable属性をtrueに -->
<div id="dragme" draggable="true" style="-webkit-user-drag: element; width: 200px; border: 1px solid gray;">
ドラッグしてね!
</div>
<div id="text"
style="width: 200px; height: 200px; border: 1px solid gray;"></div>
</body>
</html>
上のソースコードにおけるポイントを解説する。
(1) ドラッグが開始(dragstartイベント)された際、ドロップするデータをDataTransferオブジェクトにセット(setData()メソッド)する。DataTransferオブジェクトとは、ドラッグイベントのdataTransferプロパティから取得することができ、ドラッグ&ドロップによって持ち運ばれるデータを格納するためのオブジェクトだ。同オブジェクトのsetData()メソッドは、第1引数にデータの種別を表す文字列、第2引数にデータ自体を指定する。第1引数のデータ種別には任意の文字列を指定できるだけではなく、「text/plain」や「text/html」といったMIMEタイプも指定することができる。
(2) ドロップを受け付ける要素に対しては、dragoverイベント内で「イベントオブジェクト.preventDefault()」を呼び出す必要がある。これは、dragoverイベントのデフォルト動作が「ドロップ拒否」になっているため。このデフォルト動作を停止しないと、ドロップを受け付けることができない。
(3) ドロップされたら、DataTransferオブジェクトからデータを取得(getData()メソッド)して処理を行う。getData()の引数には、setData()時に指定したデータ種別(ここでは「text/plain」)を指定する。
(4) ドラッグ可能な要素には「draggable="true"」を指定する必要がある。またこのサンプルでは、現在のSafariやChromeでも動作するように、"-webkit-user-drag: element;"というWebkit固有のCSSプロパティを指定している。
さらにこのサンプルは、データ種別として「text/plain」というMIMEタイプを使用しているため、同MIMEタイプを解釈できる他のアプリケーションともデータのやり取りが可能だ。
ドラッグ&ドロップ処理で使用される一般的なMIMEタイプとしては以下のようなものが挙げられる。
- text/plain … テキストデータ
- text/html … HTML文字列
- text/xml … XML文字列
- text/uri-list … URLのリスト。各URLは改行で区切られる
残念ながら、OSネイティブのファイルをドラッグ&ドロップで取得するための汎用的な方法は存在しない。
ドラッグ&ドロップに関するその他のAPI
ドラッグ&ドロップに関するその他のAPIを駆使すれば、ドラッグ中のイメージをカスタマイズしたり、特定の操作(コピー/移動/リンクなど)以外はドロップを受け付けないようにするなど、さらに高度な処理を実現可能だ。そうした処理を実現するため、DataTransferオブジェクトに用意されているAPIを簡単に挙げておく
属性/メソッド | 説明 |
DOMString dropEffect | ドロップ操作の種別を表す。明示的に値をセットする事も可能。ドロップ先がこの種別のドロップを許可していなかったら、ドロップが受け付けられない。指定できる値(文字列)はnone、copy、link、 moveのいずれか。 |
DOMString effectAllowed | ドロップを受け付ける操作の種別を表す。指定できる値(文字列)はnone、copy、copyLink、copyMove、link、linkMove、move、all、uninitializeのいずれか。 |
DOMStringType types | 格納されているデータの種別を、文字列の擬似配列として返す |
void clearData(DOMString format) | データをクリアする。引数formatを省略すると、すべてのデータがクリアされる |
void setData(DOMString format, DOMString data) | データをセットする |
DOMString getData(DOMString format) | データを取得する |
void setDragImage(Element image, long x, long y) | ドラッグ中のイメージをimg要素でセットする(ブラウザによってはcanvasなども受け付けられる) |
void addElement(Element element) | ドラッグ対象の要素を追加する |
まとめ
今回は「HTML 5 - HTMLとXHTML向けのボキャブラリと関連API」から、HTML 5で新しく導入されたタグやAPIを中心にお伝えした。次回はアプリケーションキャッシュやWeb Storageなど、次世代のWebアプリケーションを実現するための各種APIを解説したいと思う。