JavaScript

レシピ

イベント

ドラッグ・ドロップしたときに処理を実行する

特定の要素をドラッグやドロップしたときに指定した処理を実行する方法を解説します。

この記事のポイント

  • ドラッグ・ドロップで発生するイベントは8種類
  • イベントdropを使うときはdragoverのデフォルトの挙動をキャンセルする
  • イベントdragexitは使えるブラウザが限定的なのでdragleaveを使う

目次

ドラッグ・ドロップで発生するイベントについて

マウスでHTML要素をドラッグ&ドロップすると、ドラッグを開始したり移動するときに様々なイベントが発生します。

発生するイベントの種類と条件は以下の8通りです。

イベント名発生する条件
drag対象をドラッグしている間に継続的に発生
dragendドラッグが終了したとき(マウスのボタンを離したり、Escキーを押したとき)
dragenterドラッグしている対象がドロップできる場所に入ったとき
dragexit「dragleave」と同じイベントで、現在はそちらを使います
dragleaveドラッグしている対象がドロップできる場所から離れたとき
dragoverドラッグしている対象がドロップできる場所にいる間に継続的に発生
dragstartドラッグ操作を開始したとき
dropドラッグしている対象をドロップしたとき。ただし、「dragover」のデフォルトの挙動があるときは発生しない。

ドラッグとドロップの操作はセットで扱うことが多いですが、イベント「drop」は「dragover」のデフォルトの挙動が有効になっているときは発生しないため注意が必要です。
イベント「drop」をイベントリスナーに登録するときは、「dragover」に対してpreventDefaultメソッドでデフォルトの挙動を無効にします。

以下の例は、サイの画像をドラッグ&ドロップしたときに各イベントが発生したタイミングで各イベント名をコンソール出力します。
サンプルページはこちら

HTML コード例

<article id="content1">
	<h1>JavaScriptレシピ</h1>
	<section class="dropzone">
		<div><img id="rhinos" draggable="true" src="./image/rhinos.png"></div>
		<div></div>
		<div></div>
	</section>
</article>

CSS コード例

body {
  background-color: #f7f7f7;
}
#content1 {
  padding: 20px;
  background-color: #f7f7f7;
}
#rhinos {
  width: 100px;
  height: auto;
}
.dropzone {
  display: flex;
  flex-wrap: wrap;
}
.dropzone div {
  margin-right: 2%;
  padding: 20px 1%;
  width: 20%;
  height: 100px;
  border-radius: 10px;
  border: 4px solid #73bc1d;
  background-color: #fff;
}

JavaScript コード例

window.addEventListener('DOMContentLoaded', function(){

  document.addEventListener('drag', function(e){
    console.log('drag');
  });

  document.addEventListener('dragend', function(e){
    console.log('dragend');
  });

  document.addEventListener('dragenter', function(e){
    console.log('dragenter');
  });

  document.addEventListener('dragexit', function(e){
    console.log('dragexit');
  });

  document.addEventListener('dragleave', function(e){
    console.log('dragleave');
  });

  document.addEventListener('dragover', function(e){
    e.preventDefault();
    console.log('dragover');
  });

  document.addEventListener('dragstart', function(e){
    console.log('dragstart');
  });

  document.addEventListener('drop', function(e){
    e.preventDefault();
    console.log('drop');
  });

});

このコードを実行して画像をドラッグしてみると、ドラッグしている間に発生するdragdragoverが実際に継続的に発生し続けてることが分かります。
これらのイベントを使うと、ドラッグする向きや位置(座標)を取得することもできます。

ドラッグしている対象がドロップできる場所から離れると発生するイベントdragexitdragleaveは同じタイミングで発生しますが、dragexitはFirefoxでは発生しますが、webkit系のブラウザであるChromeやSafariでは発生しません。
dragleaveはいずれのブラウザでも発生するため、こちらを使うことをお勧めします。

dragoverdropの2つのイベントのみpreventDefaultメソッドを実行しています。
dragoverは先述の通りデフォルトの挙動があるとdropが発生しないため、このメソッドを実行しています。
もう1つのdropはデフォルトの挙動が有効の場合、Firefoxなどのブラウザでドロップしたときに画像表示に切り替わってしまうこと防ぐために実行します。

画像をドラッグ・ドロップで移動させる

先ほどはドラッグ・ドロップのイベントが発生するタイミングをコンソール出力するのみでしたが、画像をドラッグ・ドロップで移動する例を紹介します。
サンプルページはこちら

HTMLとCSSは先述したコードをそのまま使います。
JavaScriptのコードは以下のようになります。

JavaScript コード例

window.addEventListener('DOMContentLoaded', function(){

  var img_element = document.getElementById('rhinos');

  img_element.addEventListener('dragstart', function(e){
    e.target.style.opacity = 0.5;
  });

  document.addEventListener('dragend', function(e){
    e.target.style.opacity = 1;
  });

  document.addEventListener('dragenter', function(e){
    if( e.target.tagName === "DIV" ) {
      e.target.style.backgroundColor = "#eee";
    }
  });

  document.addEventListener('dragleave', function(e){
    if( e.target.tagName === "DIV" ) {
      e.target.style.backgroundColor = "#fff";
    }
  });

  document.addEventListener('dragover', function(e){
    e.preventDefault();
  });

  document.addEventListener('drop', function(e){
    e.preventDefault();

    if( e.target.tagName === "DIV" ) {
      e.target.style.backgroundColor = "";
      img_element.parentNode.removeChild( img_element );
      e.target.appendChild( img_element );
    }
  });
});

このコードを実行すると、サイの画像をページに並ぶ3つのエリア間でドラッグ&ドロップして移動することができます。

dragstartdragenddragenterdragleaveの4つのイベントでは、ドラッグ操作しているときにHTML要素のCSSを動的に書き換える処理を実行します。

今回の肝はドロップ操作したときに発生するdropでの処理です。
ここではまず、e.target.tagNameからドロップした場所がdiv要素かをif文で確認します。

ドロップした場所がdiv要素だったときは、backgroundColorプロパティに空の値を設定して元のCSSで指定していた背景色(白色)に戻します。
その後、removeChildメソッドimg要素を元々あった場所から削除して、新しいドロップ先のdiv要素e.target)の中にappendChildメソッドで挿入します。

こちらの記事は役に立ちましたか?

ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。

コメントありがとうございます!
運営の参考にさせていただきます。