HTML5 Drag and Drop API

この記事では、ドラッグ&ドロップの基本について説明します。

ドラッグ可能なコンテンツを作成する

ほとんどのブラウザでは、デフォルトで選択されたテキスト、画像、リンクがドラッグ可能です。 たとえば、ウェブページ上のリンクをドラッグすると、 タイトルと URL をアドレスバーやデスクトップにドロップすると、 リンクに移動します。他の種類のコンテンツをドラッグ可能にするには、 HTML5 Drag and Drop API を使用する必要があります。

オブジェクトをドラッグ可能にするには、その要素に draggable=true を設定します。ちょうどよい 画像、ファイル、リンク、ファイルなど、あらゆるものをドラッグ可能 使用しないでください。

次の例では、並べ替えられた列を並べ替えるインターフェースを作成します。 CSS グリッドでレイアウトを適用しました。列の基本的なマークアップは次のようになります。 各列の draggable 属性を true に設定します。

<div class="container">
  <div draggable="true" class="box">A</div>
  <div draggable="true" class="box">B</div>
  <div draggable="true" class="box">C</div>
</div>

以下は、コンテナ要素とボックス要素の CSS です。この CSS に関連付けられた唯一の CSS ドラッグ機能は cursor: move です。 プロパティです。コードの残りの部分は、コンテナのレイアウトとスタイルを制御します。 ボックス要素です。

.container {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}

.box {
  border: 3px solid #666;
  background-color: #ddd;
  border-radius: .5em;
  padding: 10px;
  cursor: move;
}

この時点でアイテムをドラッグすることはできますが、他のことは起こりません。追加 JavaScript API を使用する必要があります。

ドラッグ イベントをリッスンする

ドラッグ プロセスをモニタリングするには、次のいずれかのイベントをリッスンします。

ドラッグ フローを処理するには、なんらかのソース要素(ドラッグ データ ペイロード(ドラッグされるもの)、ターゲット( キャッチアップ)。ソース要素には、ほぼすべての種類の要素を使用できます。「 target は、ユーザーがアクセスしているデータを受け入れるドロップ ゾーンまたは一連のドロップ ゾーンです 落とし穴について学びましたすべての要素をターゲットにできるわけではありません。たとえば、ターゲットが 使用できます。

ドラッグ シーケンスの開始と終了

コンテンツで draggable="true" 属性を定義したら、 各列のドラッグ シーケンスを開始する dragstart イベント ハンドラ。

このコードでは、ユーザーがドラッグを開始したときに列の不透明度を 40% に設定しています。 ドラッグ イベントが終了したら 100% に戻します。

function handleDragStart(e) {
  this.style.opacity = '0.4';
}

function handleDragEnd(e) {
  this.style.opacity = '1';
}

let items = document.querySelectorAll('.container .box');
items.forEach(function (item) {
  item.addEventListener('dragstart', handleDragStart);
  item.addEventListener('dragend', handleDragEnd);
});

結果は、次の Glitch のデモで確認できます。アイテムをドラッグして 調整できます。ソース要素に dragstart イベントがあるため、 this.style.opacity を 40% にすると、その要素が 移動対象の現在の選択範囲。アイテムをドロップすると、ソース要素が ドロップ動作を定義していなくても 100% の不透明度に戻ります。

視覚的な手掛かりを追加する

ユーザーがインターフェースの操作方法を理解できるように、 dragenterdragoverdragleave のイベント ハンドラ。この例では、 列はドラッグ可能であるだけでなく、ドロップ ターゲットになります。ユーザーが以下を行えるようサポートする ドラッグしたアイテムを 選択します。たとえば、CSS で、次のような over クラスを作成するとします。 次の要素が含まれます。

.box.over {
  border: 3px dotted #666;
}

次に、JavaScript でイベント ハンドラを設定し、over クラスを 列をドラッグして移動し、ドラッグした要素が離れたら列を削除します。イン dragend ハンドラでは、末尾のクラスも必ず削除します。 ドラッグします。

document.addEventListener('DOMContentLoaded', (event) => {

  function handleDragStart(e) {
    this.style.opacity = '0.4';
  }

  function handleDragEnd(e) {
    this.style.opacity = '1';

    items.forEach(function (item) {
      item.classList.remove('over');
    });
  }

  function handleDragOver(e) {
    e.preventDefault();
    return false;
  }

  function handleDragEnter(e) {
    this.classList.add('over');
  }

  function handleDragLeave(e) {
    this.classList.remove('over');
  }

  let items = document.querySelectorAll('.container .box');
  items.forEach(function(item) {
    item.addEventListener('dragstart', handleDragStart);
    item.addEventListener('dragover', handleDragOver);
    item.addEventListener('dragenter', handleDragEnter);
    item.addEventListener('dragleave', handleDragLeave);
    item.addEventListener('dragend', handleDragEnd);
    item.addEventListener('drop', handleDrop);
  });
});

このコードでは、以下の点について説明します。

  • デフォルトのアクション dragover イベントの dataTransfer.dropEffect プロパティを "none"dropEffect プロパティについては、このページの後半で説明します。現在のところ、 ただし、これにより drop イベントが発生しなくなります。これをオーバーライドするには e.preventDefault() を呼び出す必要があります。もう一つのベスト プラクティスは、 同じハンドラ内で false

  • dragenter イベント ハンドラは、次のように over クラスを切り替えるために使用されます。 dragoverdragover を使用すると、ユーザーが操作している間にイベントが繰り返し発生します。 ドラッグしたアイテムを列の上に配置すると、CSS クラスが切り替わります 繰り返します。ブラウザでは不必要なレンダリング処理が多く ユーザーエクスペリエンスに影響する可能性がありますすべての Pod の IP アドレスを 再描画が行われます。dragover を使用する必要がある場合は、 イベント リスナーのスロットリングまたはデバウンド

ドロップをクリアしよう

ドロップを処理するには、drop イベントのイベント リスナーを追加します。drop ブラウザのデフォルトのドロップ動作を防止する必要があります。 一般的に厄介なリダイレクトですこれを行うには、e.stopPropagation() を呼び出します。

function handleDrop(e) {
  e.stopPropagation(); // stops the browser from redirecting.
  return false;
}

新しいハンドラを他のハンドラとともに登録してください。

  let items = document.querySelectorAll('.container .box');
  items.forEach(function(item) {
    item.addEventListener('dragstart', handleDragStart);
    item.addEventListener('dragover', handleDragOver);
    item.addEventListener('dragenter', handleDragEnter);
    item.addEventListener('dragleave', handleDragLeave);
    item.addEventListener('dragend', handleDragEnd);
    item.addEventListener('drop', handleDrop);
  });

この時点でコードを実行しても、アイテムは新しい場所にドロップされません。宛先 これを行うには、DataTransfer を使用してください。 渡されます。

dataTransfer プロパティは、ドラッグ アクションで送信されたデータを保持します。dataTransfer dragstart イベントで設定され、drop イベントで読み取りまたは処理されます。発信中 e.dataTransfer.setData(mimeType, dataPayload) を使用すると、オブジェクトの MIME を設定できます。 データ ペイロードが含まれます。

この例では、ユーザーが列の順序を変更できるようにします。 そのためには、まず、ドラッグ操作が行われたときにソース要素の HTML を保存する必要があります。 開始日:

function handleDragStart(e) {
  this.style.opacity = '0.4';

  dragSrcEl = this;

  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}

drop イベントでは、ソース列の データをドロップしたターゲット列の HTML を HTML に変換します。この ユーザーが操作を行った同じ列にドロップバックしていないか 表示されます。

function handleDrop(e) {
  e.stopPropagation();

  if (dragSrcEl !== this) {
    dragSrcEl.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text/html');
  }

  return false;
}

結果は次のデモで確認できます。そのためには、 できます。Drag and Drop API はモバイルではサポートされていません。ドラッグ& B 列の上にある A 列を離すと、位置がどのように変わるかに注目してください。

その他のドラッグ プロパティ

dataTransfer オブジェクトは、ユーザーに視覚的なフィードバックを提供するプロパティを公開します。 各ドロップ ターゲットがアクションにどのように反応するかを 特定できます。

  • dataTransfer.effectAllowed 作成する「ドラッグの種類」をユーザーが操作できる要素を指定します。使用される ドラッグ&ドロップ処理モデルで dropEffect を初期化します。 dragenter イベントと dragover イベント。このプロパティには、 値: nonecopycopyLinkcopyMovelinklinkMove movealluninitialized
  • dataTransfer.dropEffect dragenterdragover の間にユーザーが受け取るフィードバックを制御します。 できます。ユーザーがターゲット要素の上にポインタを置くと、ブラウザの cursor は、コピーなど、実行する操作のタイプを示します。 動きません。この効果には、nonecopylinkmove
  • e.dataTransfer.setDragImage(imgElement, x, y) つまり、ブラウザのデフォルトの「ゴースト画像」ではなく、フィードバックを ドラッグ アイコンを設定できます。

ファイルのアップロード

この簡単な例では、ドラッグ ソースとドラッグ ターゲットの両方に列を使用しています。この ユーザーがアイテムを並べ替えるよう求める UI で発生することがあります。場合によっては インターフェースのように、ドラッグ ターゲットとソースは異なる要素タイプになる場合があります。 商品のメイン画像として 1 つの画像を 選択した画像をターゲットにドラッグします。

ドラッグ&ドロップは、ユーザーがデスクトップからアイテムを 説明します。主な違いは drop ハンドラにあります。代わりに、 dataTransfer.getData() でファイルにアクセスでき、そのデータは次の場所に格納されます。 dataTransfer.files プロパティ:

function handleDrop(e) {
  e.stopPropagation(); // Stops some browsers from redirecting.
  e.preventDefault();

  var files = e.dataTransfer.files;
  for (var i = 0, f; (f = files[i]); i++) {
    // Read the File objects in this FileList.
  }
}

詳しくは、このモジュールの カスタムのドラッグ&ドロップ

その他のリソース