ドラッグイベント

ドラッグ イベントのタイプ

ドラッグとは、ユーザーがオブジェクト上でマウス ボタンを押したまま別の場所にドラッグし、マウス ボタンを放してそこにオブジェクトを配置することを意味します。

ドラッグできるオブジェクトには、要素ノード、画像、リンク、選択したテキストなど、いくつかのタイプがあります。 Web ページでは、デフォルトでドラッグできない要素ノードを除き、他の要素 (画像、リンク、選択したテキスト) を直接ドラッグできます。要素ノードをドラッグ可能にするには、ノードの draggable 属性を true に設定します。

<div ドラッグ可能 = "true">
  この領域はドラッグできます
</div>

上記のコードの「div」ブロックは、Web ページ上でマウスで直接ドラッグできます。マウス ボタンを放すと、ドラッグ効果が消え、ブロックは元の位置に残ります。

draggable 属性は任意の要素ノードに使用できますが、画像 (<img>) とリンク (<a>) はこの属性を追加しなくてもドラッグできます。彼らにとって、この属性を使用するときは、これら 2 つの要素がドラッグされないように「false」に設定されることがよくあります。

要素ノードの「draggable」属性が「true」に設定されると、ノード内のテキストまたはサブノードをマウスで選択できなくなることに注意してください。

要素ノードまたは選択したテキストがドラッグされると、次のイベントを含むドラッグ イベントが引き続きトリガーされます。

  • drag: ドラッグ プロセス中、ドラッグされたノード上で継続的にトリガーされます (数百ミリ秒の間隔)。
  • dragstart: ユーザーがドラッグを開始すると、ドラッグされたノードでトリガーされます。このイベントの target 属性は、ドラッグされたノードです。通常、ドラッグされたデータは、このイベントの listen 関数で指定される必要があります。
  • dragend: ドラッグが終了したとき (マウス ボタンを放すか、ESC キーを押したとき)、ドラッグされたノードでトリガーされます。このイベントの target 属性は、ドラッグされたノードです。これは、「dragstart」イベントと同じノードでトリガーされます。ドラッグがウィンドウを横切るか、途中でキャンセルされるかに関係なく、dragend イベントは常にトリガーされます。
  • dragenter: 現在のノードにドラッグすると、現在のノードで 1 回トリガーされます。このイベントの target 属性は現在のノードです。通常、このイベントのリッスン関数では、ドラッグされたデータが現在のノードにドロップされることを許可するかどうかを指定する必要があります。現在のノードにこのイベントのリスニング機能がない場合、またはリスニング機能が操作を実行しない場合は、現在のノードでデータをドロップすることが許可されていないことを意味します。現在のノードへのドラッグの視覚的表示も、このイベントの listen 関数で設定されます。
  • dragover: 現在のノードの上にドラッグすると、現在のノード上で継続的にトリガーされます (数百ミリ秒ごと)。このイベントの target 属性は現在のノードです。このイベントと dragenter イベントの違いは、dragenter イベントはノードに入ったときにトリガーされ、その後ノードから出ない限り dragover イベントがトリガーされ続けることです。
  • dragleave: ドラッグ操作が現在のノードのスコープを離れると、このイベントの target 属性は現在のノードでトリガーされます。ドラッグアンドドロップ操作の現在のノードを視覚的に表示したい場合は、このイベントのリスナー関数に設定します。
  • drop: ドラッグされたノードまたは選択されたテキストがターゲット ノードにリリースされると、ターゲット ノード上でトリガーされます。現在のノードが「ドロップ」を許可していない場合、ノード上でマウス ボタンを放してもこのイベントはトリガーされないことに注意してください。ユーザーが ESC キーを押してこの操作をキャンセルした場合、このイベントはトリガーされません。このイベントのリスニング関数は、ドラッグ データを取得し、関連する処理を実行する役割を果たします。

次の例は、ドラッグされたノードの背景色を動的に変更する方法を示しています。

div.addEventListener('dragstart', function (e) {
  this.style.backgroundColor = '赤';
}、 間違い);

div.addEventListener('dragend', function (e) {
  this.style.backgroundColor = '緑';
}、 間違い);

上記のコードでは、div ノードがドラッグされると背景色が赤に変わり、ドラッグが完了すると背景色が緑に戻ります。

次の例は、現在の親ノードから別の親ノードにノードをドラッグする方法を示しています。

/* HTMLコードは以下の通り
 <div class="ドロップゾーン">
   <div id="ドラッグ可能" ドラッグ可能="true">
     このノードはドラッグできます
   </div>
 </div>
 <div class="dropzone"></div>
 <div class="dropzone"></div>
 <div class="dropzone"></div>
*/

//ドラッグされたノード
var がドラッグされました。

document.addEventListener('dragstart', function (event) {
  //ドラッグしたノードを保存する
  ドラッグ = イベント.ターゲット;
  //ドラッグしたノードの背景色が透明になります
  イベント.ターゲット.スタイル.不透明度 = 0.5;
}、 間違い);

document.addEventListener('dragend', function (event) {
  //ドラッグしたノードの背景色を通常に戻す
  イベント.ターゲット.スタイル.不透明度 = '';
}、 間違い);

document.addEventListener('dragover', function (event) {
  // ドラッグ効果がリセットされるのを防ぎ、ドラッグされたノードをターゲット ノードに配置できるようにします
  イベント.preventDefault();
}、 間違い);

document.addEventListener('dragenter', function (event) {
  //対象ノードの背景色が紫になります
  // このイベントはバブルアップするため、ノードをフィルタリングする必要があります
  if (event.target.className === 'ドロップゾーン') {
    イベント.ターゲット.スタイル.バックグラウンド = '紫';
  }
}、 間違い);

document.addEventListener('dragleave', function( イベント ) {
  //対象ノードの背景色を元の状態に戻す
  if (event.target.className === 'ドロップゾーン') {
    イベント.ターゲット.スタイル.バックグラウンド = '';
  }
}、 間違い);

document.addEventListener('drop', function( イベント ) {
  // イベントのデフォルト動作を防止します (たとえば、特定の要素ノードでリンクを開くことができます)。
  イベント.preventDefault();
  if (event.target.className === 'ドロップゾーン') {
    //対象ノードの背景色を復元
    イベント.ターゲット.スタイル.バックグラウンド = '';
    // ドラッグしたノードをターゲットノードに挿入します
    ドラッグされた.parentNode.removeChild(ドラッグされた);
    イベント.target.appendChild(ドラッグ);
  }
}、 間違い);

ドラッグ イベントに関しては、いくつか注意すべき点があります。

  • ドラッグ プロセスでは、上記のドラッグ イベントのみがトリガーされます。マウスが移動していても、マウス イベントはトリガーされません。
  • オペレーティング システムからブラウザにファイルをドラッグしても、dragstart および dragend イベントはトリガーされません。
  • ドラッグされたデータを取得する (つまり、ドラッグされた要素をドロップできるようにする) ために使用される dragenter および dragover イベントのリスニング関数。 Web ページのほとんどの領域は、ドラッグされた要素をドロップするターゲット ノードとして適していないため、これら 2 つのイベントのデフォルト設定では、現在のノードはドラッグされた要素を受け入れることができません。ターゲット ノードにデータをドロップする場合は、まずこれら 2 つのイベントのデフォルト動作を防止する必要があります。
<div ondragover="return false">
<div ondragover="event.preventDefault()">

上記のコードでは、ドラッグ イベントをキャンセルするかデフォルトの動作を防止しない限り、ドラッグされたノードを「div」ノードにドロップすることはできません。

DragEvent インターフェース

ドラッグ イベントはすべて DragEvent インターフェースを継承し、さらにそのインターフェースは MouseEvent インターフェースと Event インターフェースを継承します。

ブラウザは、ドラッグ イベントのインスタンス オブジェクトを生成するための DragEvent() コンストラクターをネイティブに提供します。

new DragEvent(タイプ、オプション)

DragEvent() コンストラクターは 2 つのパラメーターを受け入れます。最初のパラメーターはイベントのタイプを示す文字列で、2 番目のパラメーターはイベントの属性を設定するために使用されます。このパラメータはオプションです。 MouseEvent インターフェースと Event インターフェースの構成プロパティを受け入れることに加えて、構成オブジェクトは dataTransfer プロパティを null または DataTransfer インターフェースのインスタンスに設定することもできます。

DataTransfer のインスタンス オブジェクトは、ドラッグ イベントで転送されるデータの読み取りと書き込みに使用されます。詳細については、以下の「DataTransfer インターフェイス」セクションを参照してください。

データ転送インターフェイスの概要

ドラッグ イベントのすべてのインスタンスには DragEvent.dataTransfer プロパティがあり、転送する必要があるデータの読み取りおよび書き込みに使用されます。このプロパティの値は、DataTransfer インターフェイスのインスタンスです。

ブラウザーは、「DataTransfer」インスタンス オブジェクトを生成するための「DataTransfer()」コンストラクターをネイティブに提供します。

var dataTrans = 新しい DataTransfer();

DataTransfer() コンストラクターはパラメーターを受け入れません。

ドラッグされたデータは、データのタイプ (形式とも呼ばれます) とデータの値の 2 つの側面に分けられます。データのタイプは MIME 文字列 (text/plainimage/jpeg など) であり、データの値は文字列です。一般に、テキストをドラッグすると、データはそのテキストにデフォルトで設定され、リンクをドラッグすると、データはリンクの URL にデフォルトで設定されます。

ドラッグ イベントが開始されると、開発者はデータ型とデータ値を指定できます。ドラッグ プロセス中に、開発者は dragenter および dragover イベントのリスニング関数を通じてデータ型をチェックし、ドラッグされたオブジェクトをドロップできるかどうかを判断します。たとえば、リンクのみをドロップできる領域では、ドラッグされたデータ型が「text/uri-list」であるかどうかを確認します。

「drop」イベントが発生すると、listen 関数がドラッグされたデータを取り出して処理します。

DataTransfer のインスタンス プロパティ

DataTransfer.dropEffect

DataTransfer.dropEffect プロパティは、ドラッグされたノードをドロップするときの効果を設定するために使用されます。これは、関連する領域をドラッグするときのマウスの形状に影響します。次の値を取ることができます。

  • コピー: ドラッグしたノードをコピーします。
  • 移動: ドラッグしたノードを移動します
  • リンク: ドラッグしたノードへのリンクを作成します。
  • none: ドラッグしたノードをドロップできません

上記以外の値の設定は無効となります。

target.addEventListener('dragover', function (e) {
  e.preventDefault();
  e.stopPropagation();
  e.dataTransfer.dropEffect = 'コピー';
});

上記のコードでは、ドラッグされた要素が「ドロップ」されると、ノードは受け入れられた領域にコピーされます。

通常、d​​ropEffect 属性は、dragenter および dragover イベントの listen 関数で設定されます。 dragstartdrag、および dragleave の 3 つのイベントについては、この属性は効果がありません。この属性はドラッグされたノードを受け入れる領域に対してのみ有効であるため、ドラッグされたノード自体に対しては無効です。ターゲット領域に入ると、ドラッグ動作は設定された効果に初期化されます。

DataTransfer.effectAllowed

DataTransfer.effectAllowed プロパティは、このドラッグで許可される効果を設定します。次の値を取ることができます。

  • コピー: ドラッグしたノードをコピーします。
  • 移動: ドラッグしたノードを移動します
  • リンク: ドラッグしたノードへのリンクを作成します。
  • copyLink: コピーまたはリンクを許可します
  • copyMove: copy または move を許可します
  • linkMove: link または move を許可します
  • all: すべての効果を許可します
  • none: ドラッグしたノードをドロップできません
  • 初期化されていない: デフォルト値、「all」と同等

エフェクトが許可されていない場合、ユーザーはターゲット ノードでそのエフェクトを実現できません。

このプロパティと dropEffect プロパティは表裏の関係にあります。前者はドラッグされたノードで許可される効果を設定し、後者はドラッグされた領域の効果を設定します。これらはよく一緒に使用されます。

dragstart イベントの listen 関数を使用して、このプロパティを設定できます。他のイベントリスニング関数でこのプロパティを設定することは無効です。

source.addEventListener('dragstart', function (e) {
  e.dataTransfer.effectAllowed = '移動';
});

target.addEventListener('dragover', function (e) {
  e.dataTransfer.dropEffect = '移動';
});

「dropEffect」属性と「effectAllowed」属性のいずれかが「none」である限り、ターゲット ノード上で「drop」操作を完了することはできません。

DataTransfer.ファイル

DataTransfer.files プロパティは、ドラッグ アンド ドロップ操作で転送するために使用できるローカル ファイルのセットを含む FileList オブジェクトです。このドラッグにファイルが含まれない場合、このプロパティは空の FileList オブジェクトになります。

以下はドラッグされたファイルを受信する例です。

// HTMLコードは以下の通り
// <div id="output" style="min-height: 200px;border: 1px 単色黒;">
// ここにファイルをドラッグします
// </div>

var div = document.getElementById('output');

div.addEventListener("ドラレンジャー", function( イベント ) {
  div.textContent = '';
  イベント.stopPropagation();
  イベント.preventDefault();
}、 間違い);

div.addEventListener("ドラッグオーバー", function( イベント ) {
  イベント.stopPropagation();
  イベント.preventDefault();
}、 間違い);

div.addEventListener("ドロップ", function( イベント ) {
  イベント.stopPropagation();
  イベント.preventDefault();
  var ファイル =event.dataTransfer.files;
  for (var i = 0; i < files.length; i++) {
    div.textContent += files[i].name + ' ' + files[i].size + 'byte\n';
  }
}、 間違い);

上記のコードでは、ドラッグされたファイルの情報が dataTransfer.files プロパティを通じて読み取られます。ファイルの内容を読み取りたい場合は、FileReader オブジェクトを使用する必要があります。

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

  var fileList = e.dataTransfer.files;
  if (fileList.length > 0) {
    var ファイル = ファイルリスト[0];
    var リーダー = 新しい FileReader();
    Reader.onloadend = function(e) {
      if (e.target.readyState === FileReader.DONE) {
        var コンテンツ = リーダー.結果;
        div.innerHTML = 'ファイル: ' + file.name + '\n\n' + コンテンツ;
      }
    }
    Reader.readAsBinaryString(file);
  }
});

DataTransfer.types

DataTransfer.types プロパティは読み取り専用の配列で、各メンバーはドラッグされたデータ形式 (通常は MIME 値) である文字列です。たとえば、テキストをドラッグすると、対応するメンバーは「text/plain」になります。

以下は、「dataTransfer」属性のタイプをチェックして、現在のノードで「drop」操作の実行が許可されているかどうかを判断する例です。

関数に含まれる(リスト, 値){
  for (var i = 0; i < list.length; ++i) {
    if(list[i] === value) は true を返します。
  }
  false を返します。
}

関数 doDragOver(event) {
  var isLink = contains(event.dataTransfer.types, 'text/uri-list');
  if (isLink)event.preventDefault();
}

上記のコードでは、ドラッグされたノードの 1 つがリンクである場合にのみ、現在のノードをドロップできます。

DataTransfer.items

DataTransfer.items プロパティは配列状の読み取り専用オブジェクト (DataTransferItemList インスタンス) を返し、各メンバーは今回ドラッグされるオブジェクト (DataTransferItem インスタンス) です。このドラッグにオブジェクトが含まれていない場合は、空のオブジェクトが返されます。

DataTransferItemList インスタンスには、次のプロパティとメソッドがあります。

  • length: メンバーの数を返します。
  • add(data, type): コンテンツとタイプを指定した文字列(text/htmltext/plainなど)をメンバーとして追加します
  • add(file): add メソッドの別の使用法。ファイルをメンバーとして追加します。
  • remove(index): 指定した位置のメンバーを削除します
  • clear(): すべてのメンバーを削除します

DataTransferItem インスタンスには次のプロパティとメソッドがあります。

  • kind: メンバーのタイプ (string または file) を返します。
  • type: メンバーのタイプ (通常は MIME 値) を返します。
  • getAsFile(): ドラッグされたファイルがファイルの場合はファイルを返し、それ以外の場合は null を返します。
  • getAsString(callback): ドラッグされた文字列が文字列の場合、その文字を指定されたコールバック関数に渡して処理します。このメソッドは非同期であるため、コールバック関数を渡す必要があります。

以下に例を示します。

div.addEventListener('drop', function (e) {
  e.preventDefault();
  if (e.dataTransfer.items != null) {
    for (var i = 0; i < e.dataTransfer.items.length; i++) {
      console.log(e.dataTransfer.items[i].kind + ': ' + e.dataTransfer.items[i].type);
    }
  }
});

DataTransfer のインスタンス メソッド

DataTransfer.setData()

DataTransfer.setData() メソッドは、ドラッグ イベントによって運ばれるデータを設定するために使用されます。このメソッドには戻り値がありません。

event.dataTransfer.setData('text/plain', 'ドラッグするテキスト');

上記のコードは、現在のドラッグ イベントにプレーン テキスト データを追加します。

このメソッドは 2 つのパラメータを受け入れます。どちらも文字列です。最初のパラメータはデータ型 (「text/plain」など) を表し、2 番目のパラメータは特定のデータです。指定されたタイプのデータが dataTransfer 属性に存在しない場合は、データが追加されます。存在しない場合は、元のデータが新しいデータに置き換えられます。

テキスト ボックスをドラッグするか、選択したテキストをドラッグすると、手動で指定しなくても、対応するテキスト データがデフォルトで dataTransfer プロパティに追加されます。

<div ドラッグ可能 = "true">
  ああ
</div>

上記のコードでは、<div> 要素をドラッグすると、自動的にテキスト データ aaa が表示されます。

元のデータを置き換えるには、setData メソッドを使用します。

<div
  ドラッグ可能 = "true"
  ondragstart="event.dataTransfer.setData('text/plain', 'bbb')"
>
  ああ
</div>

上記のコードでは、ドラッグされたデータは実際には「aaa」ではなく「bbb」です。

次に、他の種類のデータを追加します。 text/plain が最も一般的にサポートされている形式であるため、互換性を確保するために、最後に必ずプレーン テキスト形式のデータを保存することをお勧めします。

var dt = イベント.データ転送;

//リンクを追加
dt.setData('text/uri-list', 'http://www.example.com');
dt.setData('text/plain', 'http://www.example.com');

//HTMLコードを追加
dt.setData('text/html', 'こんにちは、<strong>見知らぬ人</strong>');
dt.setData('text/plain', 'こんにちは、<strong>見知らぬ人</strong>');

//画像のURLを追加
dt.setData('text/uri-list', imageurl);
dt.setData('text/plain', imageurl);

データは複数の形式で一度に提供できます。

var dt = イベント.データ転送;
dt.setData('application/x-bookmark',bookmarkString);
dt.setData('text/uri-list', 'http://www.example.com');
dt.setData('text/plain', 'http://www.example.com');

上記のコードでは、同じイベントに 3 種類のデータを保存することで、ドラッグ イベントは異なるオブジェクトに異なる値を「ドロップ」できます。最初の形式は、デフォルトではブラウザで読み取ることができないカスタム形式であることに注意してください。これは、特定のコードがデプロイされたノードのみがこのデータを「ドロップ」(読み取り)できることを意味します。

DataTransfer.getData()

DataTransfer.getData() メソッドは、文字列 (データ型を表す) をパラメータとして受け取り、イベントによって運ばれる指定された型のデータ (通常は setData メソッドを使用して追加されたデータ) を返します。指定された型のデータが存在しない場合は、空の文字列が返されます。通常、データは「drop」イベントがトリガーされた後にのみ取得できます。

以下は、指定されたタイプのデータを取得するために使用される「drop」イベントのリスニング関数です。

関数 onDrop(event) {
  var data = events.dataTransfer.getData('text/plain');
  イベント.ターゲット.テキストコンテンツ = データ;
  イベント.preventDefault();
}

上記のコードは、ドラッグ イベントのテキスト データを取得し、現在のノードのテキスト コンテンツに置き換えます。ユーザーがリンクをドラッグすると、ブラウザはデフォルトで現在のウィンドウでリンクを開くため、この時点でブラウザのデフォルトの動作をキャンセルする必要があることに注意してください。

getData メソッドは文字列を返します。複数のデータが含まれている場合は、手動で解析する必要があります。

関数 doDrop(イベント) {
  var Lines = events.dataTransfer.getData('text/uri-list').split('\n');
  for (let 行) {
    let link = document.createElement('a');
    リンク.href = 行;
    link.textContent = 行;
    イベント.ターゲット.appendChild(リンク);
  }
  イベント.preventDefault();
}

上記のコードでは、「getData」メソッドはリンクのセットを返しますが、それ自体を解析する必要があります。

type 値は「URL」として指定され、最初の有効なリンクを取得できます。

var link =event.dataTransfer.getData('URL');

次の例では、複数の種類のデータからデータを抽出します。

関数 doDrop(イベント) {
  var type =event.dataTransfer.types;
  varsupportedTypes = ['text/uri-list', 'text/plain'];
  types =supportedTypes.filter(function (value) {types.includes(value) });
  if (型.長さ) {
    var data = events.dataTransfer.getData(types[0]);
  }
  イベント.preventDefault();
}

DataTransfer.clearData()

DataTransfer.clearData() メソッドは、文字列 (データ タイプを表す) をパラメータとして受け取り、イベントによって運ばれる指定されたタイプのデータを削除します。タイプが指定されていない場合は、すべてのデータが削除されます。指定された型が存在しない場合、このメソッドを呼び出しても効果はありません。

event.dataTransfer.clearData('text/uri-list');

上記のコードは、イベントによって運ばれる text/uri-list タイプのデータをクリアします。

このメソッドはドラッグされたファイルを削除しないため、このメソッドを呼び出した後でも、DataTransfer.types プロパティは引き続き Files タイプを返す可能性があります (ファイルのドラッグがある場合)。

このメソッドは、ドラッグ操作のデータを書き込むことができる唯一の時間であるため、「dragstart」イベントのリッスン関数でのみ使用できることに注意してください。

DataTransfer.setDragImage()

ドラッグ プロセス中 (「dragstart」 イベントがトリガーされた後)、ブラウザーにはマウスとともに移動してドラッグされたノードを表す画像が表示されます。この画像は自動的に作成され、通常はドラッグされたノードの外観を表示するため、自分で設定する必要はありません。

DataTransfer.setDragImage() メソッドはこの画像をカスタマイズできます。 3 つのパラメータを受け入れます。最初のパラメータは <img> ノードまたは <canvas> ノードです。省略または null の場合、2 番目と 3 番目のパラメータはイメージに対するマウスの相対値になります。と左上隅の縦座標。

以下に例を示します。

/* HTMLコードは以下の通り
 <div id="drag-with-image" class="dragdemo" draggable="true">
   私を引きずってください
 </div>
*/

var div = document.getElementById('画像付きドラッグ');
div.addEventListener('dragstart', function (e) {
  var img = document.createElement('img');
  img.src = 'http://パス/to/img';
  e.dataTransfer.setDragImage(img, 0, 0);
}、 間違い);

作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0