連載
» 2011年09月13日 00時00分 公開

連載:人気順に説明する初めてのHTML5開発:アドインなしで実現可能! ドラッグ&ドロップを使いこなそう (1/2)

ブラウザ標準の機能のみでドラッグ&ドロップを実装できる、HTML5の「Drag and Drop API」の使い方を説明。

[ナオキ(監修:山田祥寛),WINGSプロジェクト(http://www.wings.msn.to/)]
連載:人気順に説明する初めてのHTML5開発
業務アプリInsider/Insider.NET

powered by Insider.NET

「連載:人気順に説明する初めてのHTML5開発」のインデックス

連載目次

 ドラッグ&ドロップと聞くと、大抵の方はクライアント・アプリケーションでの操作と感じるだろう。従来、たいていのブラウザはドラッグ&ドロップには対応しておらず、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のドラッグ&ドロップはクソだ」)。 それでは、実際にドラッグ&ドロップの処理について見ていこう。

■ブラウザで実装するドラッグ&ドロップ

 最初に、ブラウザ上で実装する基本的なドラッグ&ドロップの例だ。

 サンプルを実行すると、画像と青枠が表示される。画像を青色の部分にドラッグ&ドロップすると、画像を移動できる。実行結果は、以下のとおり。

図1 ドラッグ実行例

図2 ドロップ結果

 具体的なコードは、以下のとおりである。

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

画像をドラッグ&ドロップするサンプル(dnd1.htm

(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メソッドを呼び出すことになる。このお作法が必要な点には注意が必要だ。

 以上を理解したうえで、次のページでは、より実用的なドラッグ&ドロップのサンプルを示す。

       1|2 次のページへ

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。