PR

デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI

2013年3月1日(金)
山田 祥寛(YAMADA, Yoshihiro)

ドラッグ&ドロップAPIは、名前のとおり、ページ上のさまざまな要素をマウスでドラッグ&ドロップできるようにするための仕組みです。

一例を挙げると、ドラッグ&ドロップ機能とFile APIとを組み合わせることで、ブラウザに対してドロップしたファイルをそのままサーバーにアップロードできるようになるなど、よりデスクトップアプリ的な仕掛けを実装できるようになります。

[第8回目次]
  • 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>
図1:要素がマウスでドラッグ可能に(クリックで拡大)

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:画像を指定の領域でドロップすると、画像を移動(クリックで拡大)

ドラッグ&ドロップに関するイベントとしては、以下のようなものが用意されています。

表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メソッドを呼び出しているのは、デフォルトの動作ではブラウザ標準の挙動が優先されてしまい、ドロップ操作が拒否されてしまうからです。そのため、ここで明示的にブラウザの挙動をキャンセルしておきます。

Think IT会員限定特典
  • デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI

著者
山田 祥寛(YAMADA, Yoshihiro)
WINGSプロジェクト

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表:山田祥寛)。おもな活動は、Web開発分野の書籍/雑誌/Web記事の執筆。ほかに海外記事の翻訳、講演なども幅広く手がける。2011年3月時点での登録メンバは36名で、現在もプロジェクトメンバーを募集中。

連載記事一覧

Think IT会員サービスのご案内

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスのご案内

関連記事