ドラッグ&ドロップとは、ウェブページ内の要素やローカル環境に保存されたファイルなどのデータを、 マウスで引きずるように移動させて他の場所に置く操作のことです。 HTML5以前にも、mousedownやmouseupなどのイベントで実現することはできましたが、 HTML5ではドラッグ&ドロップ専用の新しいイベントや新しいメソッド・属性が追加されています。
ドラッグ&ドロップを理解するには、ドラッグ操作とドロップ操作を分けて考えると理解しやすいでしょう。 ドラッグ操作は要素などのデータをマウスでつかんで引きずるように動かすこと、 ドロップ操作はその動かしたデータをドロップ先の要素内に配置することです。
HTML側では、ドラッグする要素にdraggable属性を指定します。 draggable属性の値には、true・false・値なしのいずれかを指定します。 値を指定しない場合にはデフォルト動作となります。
href属性が指定されたa要素、および、src属性が指定されたimg要素は、デフォルトでドラッグ可となっています。 それ以外の要素は、デフォルトではドラッグ不可です。
HTML
<div id="apple" draggable="true">りんご</div>
昔はdropzone属性で「ここにドロップできる」を表す考え方もありましたが、現在は主要ブラウザで実用されていません。実務では、dragoverなどでevent.preventDefault()を呼んで「ここにドロップOK」を許可する方法が一般的です。
そのためこのページのサンプルでも、dropzoneは使わずに「ドロップ先の要素でdragoverを受け取り、preventDefault()する」流れで説明します。
※補足:ドラッグ中に「コピー/移動」の見た目を変えたい場合は、DataTransfer.dropEffect や effectAllowed を使って制御します。
JavaScript側では、ドラッグ開始時にDataTransferというオブジェクトにドラッグするデータをセットしておき、 ドロップ時にそのデータを取り出して、ドラッグデータをドロップ先へ受け渡すことでドラッグ&ドロップを実現します。
この際、データのセットに使用するのがsetData()メソッド、 データの取得に使用するのがgetData()メソッドです。
JavaScript
// データをセットする(dragstart など)
event.dataTransfer.setData(format, data);
// データを取得する(drop など)
data = event.dataTransfer.getData(format);
「何が専用で、どれを使えばいいか」を忘れたときに見返す用の一覧です。
draggable="true"draggable="false"draggable(値なし)aやimgなどはデフォルトでドラッグ可なことがあります)。dragstartdataTransfer に渡すデータを入れるのが定番です。dragdragenterdragleavedragoverevent.preventDefault() しないと、基本的にドロップできません。dropgetData() で受け取って、DOMに追加したり、処理を実行します。dragendondragstartdragstart をHTML属性で受け取る書き方です。ondragoverdragover をHTML属性で受け取る書き方です(ドロップ可能にするなら preventDefault() がほぼ必須)。ondropdrop をHTML属性で受け取る書き方です。ondragenter / ondragleave / ondrag / ondragendaddEventListener を使う方法もあります)。event.dataTransfer(DataTransfer)DataTransfer.setData(format, data)"text/plain" が分かりやすいです。DataTransfer.getData(format)setData と同じ format を指定します)。DataTransfer.clearData([format])DataTransfer.dropEffectDataTransfer.effectAllowedDataTransfer.types"text/plain" など)。DataTransfer.filesDataTransfer.itemsevent.preventDefault()dragover で呼ぶのが定番です。event.currentTargetevent.targetドラッグ&ドロップは、7つのイベントをきっかけにして動きます。イベントが起きたタイミングで DataTransfer の中身を入れたり取り出したりして、ドロップ先の動きをJavaScriptで決めるイメージです。
ポイントは「イベント名を暗記する」よりも、どんな順番で起きるかをつかむことです。
dragstart(つかんだ瞬間)event.dataTransfer.setData() を使って「運ぶ中身」を入れておくのが定番です。drag(運んでいる最中)dragenter(ドロップ先に入った瞬間)dragover(ドロップ先の上にいる間)event.preventDefault() しないと、基本的にドロップできません(ブラウザの既定動作で拒否されます)。dragleave(ドロップ先から出た瞬間)drop(落とした瞬間)event.dataTransfer.getData() で中身を取り出して、要素を追加したり処理を実行します。dragend(終わったとき)迷ったら、まずは dragstart / dragover / drop の3つを押さえると動かせます。
ドラッグ操作では、ドラッグするデータをDataTransferオブジェクトにセットすることで、ドロップ先に受け渡すことのできる状態にします。
JavaScript
// ドラッグ開始時の処理
function f_dragstart(event){
//ドラッグするデータのid名をDataTransferオブジェクトにセット
event.dataTransfer.setData("text/plain", event.target.id);
};
色付きのボックスを左のボックスから右のボックスに移動できます。
HTML
<div id="box1">
<div id="item" draggable="true" ondragstart="drag(event)"></div>
</div>
<div id="box2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
CSS
#box1, #box2 {
float: left;
width: 70px;
height: 70px;
border: 1px solid #999;
}
#item {
margin: 3px;
width: 50px;
height: 50px;
background-color: #900;
border: 1px solid #999;
}
JavaScript
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text/plain", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
let data = ev.dataTransfer.getData("text/plain");
ev.currentTarget.appendChild(document.getElementById(data));
}