ブラウザ標準の機能のみでドラッグ&ドロップを実装できる、HTML5の「Drag and Drop API」の使い方を説明。
powered by Insider.NET
ドラッグ&ドロップと聞くと、大抵の方はクライアント・アプリケーションでの操作と感じるだろう。従来、たいていのブラウザはドラッグ&ドロップには対応しておらず、Webページ上でドラッグ&ドロップ機能を実装するには、jQueryプラグインなど外部ライブラリを利用する必要があった。しかしHTML5では、仕様として「Drag and Drop API」が定義された。これを利用することで、ライブラリに頼ることなく、ブラウザ標準の機能のみでドラッグ&ドロップを実装できるようになる。
Drag and Drop APIは次の表のとおり、現在、リリースされている主要ブラウザでも、ほとんど実装済みだ。
ブラウザ | 対応バージョン |
---|---|
Internet Explorer | 5.5以降 |
Firefox | 3.5以降 |
Chrome | 4以降 |
Safari | 3.1以降 |
Opera | 未実装 |
主要ブラウザにおけるDrag and Drop APIの実装状況 |
HTML5のDrag and Drop APIは、Insider.NETの読者諸氏ならば習得が容易なはずだ。なぜなら、ドラッグ&ドロップの実装方法が.NET FrameworkのWindowsフォーム・アプリケーションのそれと類似しているからだ。
HTML 5のDrag and Drop APIの実装方法は「ドラッグ操作」と「ドロップ操作」に切り分けて考える必要があるが、この考え方はずばりWindowsフォーム・アプリケーションのそれと同様である。これは、Drag and Drop APIの設計にマイクロソフトが大きな影響を与えている点に由来している。 WHATWG(Web Hypertext Application Technology Working Group)がHTML5の仕様策定を進める際、「先進的な機能を実装しているブラウザの挙動を規格化する」という基本理念があった。マイクロソフトでは、IE5の際に「IE独自実装」という形でドラッグ&ドロップ機能を実装しており(これは.NET FrameworkのWindowsフォーム・アプリケーションでの実装のベースとなっていると著者は感じている)、WHATWGの理念によって、この機能がHTML5のドラッグ&ドロップの基盤となったというわけだ。このような流れを経て導入された機能であるため、HTML5のDrag and Drop APIはIE6でも利用できるというメリットもある。 ブラウザ・シェアなどから考えるとDrag and Drop APIは、HTML5の仕様の中で一番実装しやすい機能だともいえるだろう。しかしながら、一見、良いことのように感じるかもしれないが、クライアント・アプリケーションのような多数のイベントによる処理の記載の煩雑さについては否定的な意見も出ている(参考:「本の虫: QuirksBlog: HTML5のドラッグ&ドロップはクソだ」)。 それでは、実際にドラッグ&ドロップの処理について見ていこう。
最初に、ブラウザ上で実装する基本的なドラッグ&ドロップの例だ。
サンプルを実行すると、画像と青枠が表示される。画像を青色の部分にドラッグ&ドロップすると、画像を移動できる。実行結果は、以下のとおり。
具体的なコードは、以下のとおりである。
<p>枠から枠にドラッグ&ドロップを実施できます</p>
<!-- (1)ドラッグ元とドラッグ先の要素にイベントや属性を指定 -->
<div style="width:700px; height:210px;">
<img id="cat1pic" src="cat1.jpg" draggable="true" ondragstart="DragStart(event)" />
</div>
<div id="drop"
style="width:700px; height:300px; background-color:blue; padding:10px;"
ondragover="DragOver(event)" ondrop="Drop(event)" >
</div>
<script type="text/javascript">
// (2)ドラッグ開始時にデータの値を設定する
function DragStart(event) {
event.dataTransfer.setData("text", event.target.id);
}
// (3)ドロップ時に元のドラッグ値を取得し、現在の要素上に入れ子で保存する
function Drop(event) {
var id = event.dataTransfer.getData("text");
var elm = document.getElementById(id);
event.currentTarget.appendChild(elm);
event.preventDefault();
}
// (4)ブラウザ標準のドロップ動作をキャンセル
function DragOver(event) {
event.preventDefault();
}
</script>
(1)ドラッグ元とドラッグ先の要素にイベントや属性を指定
draggable属性とは、すべての要素で指定できる属性で、指定した要素をドラッグによって移動できるか否かを指定する。サンプルでは<img>要素に対してdraggable属性を「true」で定義している。draggable属性の書式は以下のとおりだ。
書式 | 概要 |
---|---|
draggable="true" | ドラッグを実施する |
draggable="false" | ドラッグを実施しない |
draggable="" | デフォルトの動作を実施 |
draggable属性の書式と概要 |
デフォルトの動作は要素によって決まる。基本的にほとんどの要素ではドラッグを実施しない(=false)設定となっているが、例外として<a>要素や<img>要素では「ドラッグは有効(=true)」がデフォルトの挙動である。 続いて、<img>要素と<div>要素にドラッグ開始とドロップ開始のイベントを指定する。ドラッグ&ドロップで利用できるイベントは以下のとおり。
種類 | イベント名 | 発生タイミング | |
---|---|---|---|
ドラッグ | dragstart | ドラッグ開始時 | |
drag | ドラッグ中 | ||
dragend | ドラッグ終了時 | ||
ドロップ | dragenter | ドラッグ元の要素がドロップ可能な要素に入ったとき | |
dragover | ドラッグ元の要素がドロップ可能な要素内にあるとき | ||
dragleave | ドラッグ元の要素がドロップ可能な要素から出たとき | ||
drop | ドロップ中 | ||
ドラッグ&ドロップ操作に関するイベント |
ドラッグとドロップに関するイベントには、「ondragenter」や「ondrop」など、各イベントに対応する「on〜」という属性が用意されている。これらの属性に、イベント・ハンドラとなる関数の名前を指定し、イベントごとの動作を各関数に実装する。ドラッグ中はMouseLeaveやMouseEnterなどのマウス・イベントなどは発生しない点には注意が必要だ。
(2)ドラッグ開始時にデータの値を設定する
続いて、(2)〜(3)がドラッグ&ドロップを処理する一連のイベント・ハンドラだ。前述したように、ドラッグ&ドロップ操作では、ドラッグ操作とドロップ操作を分けて、実装するのが基本である。用例では、ドラッグ開始時にドラッグ元の要素を記録し((2))、ドロップ時に要素の移動処理((3))を行っている。 それでは、(2)のドラッグ開始時の操作(=DragStart関数)から見ていこう。
ここでポイントとなるのは、DataTransferオブジェクトだ。DataTransferオブジェクトはドラッグ&ドロップで受け渡しに関するデータを管理するオブジェクトだ。DataTransferオブジェクトが提供するメソッドとプロパティは以下のとおり。
メソッド/プロパティ名 | 概要 |
---|---|
setData(key, value) | ドラッグとドロップにより受け渡しするデータをキー/値のペアで設定 |
getData(key) | setDataメソッドで設定したデータを、キー(text/url)を指定して取得。後述するとおり、MIMEタイプを指定することで外部のタブやブラウザからのドロップ・データを取得することもできる |
clearData() | データをクリア |
setDragImage(image, x, y) | ドラッグ中のドラッグ・アイコン画像を<img>要素を用いて指定。x/yの座標軸を指定し、表示位置を調整することもできる |
addElement(element) | ドラッグ元の要素を指定 |
types | setDataメソッドでセットされたデータの形式を取得 |
files | ローカル・ファイルからドラッグされたデータを参照 |
dropEffect | ドラッグ中のマウス・アイコンにドロップ結果の種類を設定。画像をアプリケーション内でコピーする(copy)、画像のURLをリンクとして貼り付ける(link)、画像を移動させる(move)など、処理に応じて設定が可能 |
effectAllowed | ドロップ操作を受け付ける要素における操作の種類を設定。ドロップできない(none)、全ての操作を受け付ける(all)、リンクだけを表示できる(link)などの設定が可能 |
ドロップ操作に関するイベント |
この例では、setDataメソッドでDataTransferオブジェクトにドラッグ元要素のID値を設定し、ドロップ時に処理すべき要素を退避させている(この情報は、後からDrop関数で利用できる)。要素のIDは「event.target.id」で取得可能だ。また、setDataメソッドではキーとして「text」または「url」しか指定できないので注意されたい。
(3)ドロップ時に元のドラッグ値を取得し現在の要素上に入れ子で保存する
Drop関数はドロップ時に呼び出されるイベント・ハンドラだ。最初にgetDataメソッドで(2)で設定した値(ID)を取得している。続いて、取得したIDを基にgetElementByIdメソッドで要素のノードを取得し、ドロップ先の要素の子要素として追加している。 ドロップ先の要素はevent.currentTargetプロパティで取得できる。つまり、「event.currentTarget.appendChild(……)」で、ドロップ先要素の最後の子要素にドロップ元要素を追加する、という意味になる。 なお、最後に、デフォルトの動作を抑止するためにpreventDefaultメソッドを使用してイベントを停止している点にも注目してほしい。さもないと、Dropイベントがループで発生し、正しくドロップ操作が行われない。
(4)ブラウザ標準のドロップ動作をキャンセル
DragOver関数はドロップ可能な要素内にあるときに呼び出されるイベント・ハンドラだ。dragoverイベントは既定の設定でドロップを受け付けないため、preventDefaultメソッドを使用してブラウザ標準のドロップ動作をキャンセルしている。これによりドロップ先の要素がドロップ操作を受け付けるようになる。
Drag and Drop APIにおいて、dragoverイベントは既定のアクションが要素をドロップさせないことにあるため、preventDefaultメソッドを呼び出すことになる。このお作法が必要な点には注意が必要だ。
以上を理解したうえで、次のページでは、より実用的なドラッグ&ドロップのサンプルを示す。
Copyright© Digital Advantage Corp. All Rights Reserved.