web-dev-qa-db-ja.com

ブラウザがドラッグアンドドロップされたファイルをロードするのを防ぎます

Html5ドラッグアンドドロップアップローダーをページに追加しています。

ファイルがアップロード領域にドロップされると、すべてがうまく機能します。

ただし、誤ってファイルをアップロード領域の外にドロップすると、ブラウザーはローカルファイルを新しいページのようにロードします。

この動作を防ぐにはどうすればよいですか?

ありがとう!

167
Travis

すべてのドラッグオーバーおよびドロップイベントでpreventDefault()を呼び出すウィンドウにイベントリスナーを追加できます。
例:

window.addEventListener("dragover",function(e){
  e = e || event;
  e.preventDefault();
},false);
window.addEventListener("drop",function(e){
  e = e || event;
  e.preventDefault();
},false);
261
Digital Plane

いじくり回した後、これが最も安定したソリューションであることがわかりました。

var dropzoneId = "dropzone";

window.addEventListener("dragenter", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
}, false);

window.addEventListener("dragover", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
});

window.addEventListener("drop", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
});
<div id="dropzone">...</div>

ウィンドウでeffectAllowdropEffectの両方を無条件に設定すると、プロパティが新規に設定されているかどうかにかかわらず、ドロップゾーンはd-n-dを受け入れなくなります。

29
Axel Amthor

JQueryの正しい答えは次のとおりです。

$(document).on({
    dragover: function() {
        return false;
    },
    drop: function() {
        return false;
    }
});

ここでreturn falseevent.preventDefault()およびevent.stopPropagation()として動作します。

8
VisioN

一部の要素でのみドラッグアンドドロップを許可するには、次のようにします。

window.addEventListener("dragover",function(e){
  e = e || event;
  console.log(e);
  if (e.target.tagName != "INPUT") { // check which element is our target
    e.preventDefault();
  }
},false);
window.addEventListener("drop",function(e){
  e = e || event;
  console.log(e);
  if (e.target.tagName != "INPUT") {  // check which element is our target
    e.preventDefault();
  }  
},false);
8
enthus1ast

これを試して:

document.body.addEventListener('drop', function(e) {
    e.preventDefault();
}, false);
2
moe

既定ですべてのドラッグアンドドロップ操作を禁止することは、望んでいない場合があります。少なくとも一部のブラウザーでは、ドラッグソースが外部ファイルかどうかを確認できます。この StackOverflow answer には、ドラッグソースが外部ファイルであるかどうかを確認する関数が含まれています。

Digital Planeの答えを修正すると、次のようなことができます:

function isDragSourceExternalFile() {
     // Defined here: 
     // https://stackoverflow.com/a/32044172/395461
}

window.addEventListener("dragover",function(e){
    e = e || event;
    var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
    if (IsFile) e.preventDefault();
},false);
window.addEventListener("drop",function(e){
    e = e || event;
    var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
    if (IsFile) e.preventDefault();
},false);
2
Shannon

他のいくつかの回答で概説されている「ターゲットを確認する」方法に基づいて、より一般的/機能的な方法を次に示します。

function preventDefaultExcept(predicates) {
  return function (e) {
    var passEvery = predicates.every(function (predicate) { return predicate(e); })
    if (!passEvery) {
      e.preventDefault();
    }
  };
}

次のように呼び出されます:

function isDropzone(e) { return e.target.id === 'dropzone'; }
function isntParagraph(e) { return e.target.tagName !== 'p'; }

window.addEventListener(
  'dragover',
  preventDefaultExcept([isDropzone, isntParagraph])
);
window.addEventListener(
  'drop',
  preventDefaultExcept([isDropzone])
);
1
scott_trinh

複数のアップロード領域にクラスセレクターを使用しているため、ソリューションはこのあまり純粋でない形式を取りました。

Axel Amthorの回答に基づき、jQueryに依存($にエイリアス)

_stopBrowserFromOpeningDragAndDropPDFFiles = function () {

        _preventDND = function(e) {
            if (!$(e.target).is($(_uploadBoxSelector))) {
                e.preventDefault();
                e.dataTransfer.effectAllowed = 'none';
                e.dataTransfer.dropEffect = 'none';
            }
        };

        window.addEventListener('dragenter', function (e) {
            _preventDND(e);
        }, false);

        window.addEventListener('dragover', function (e) {
            _preventDND(e);
        });

        window.addEventListener('drop', function (e) {
            _preventDND(e);
        });
    },
0
hngr18

ページの幅と高さを埋めるHTML objectembed)があります。 @ digital-planeによる回答は、通常のWebページで機能しますが、ユーザーが埋め込みオブジェクトにドロップした場合は機能しません。そのため、別のソリューションが必要でした。

イベントキャプチャフェーズ を使用するように切り替えると、埋め込みオブジェクトがイベントを受け取る前にイベントを取得できます(イベントリスナー呼び出しの最後にtrue値に注意してください)。

// document.body or window
document.body.addEventListener("dragover", function(e){
  e = e || event;
  e.preventDefault();
  console.log("over true");
}, true);

document.body.addEventListener("drop", function(e){
  e = e || event;
  e.preventDefault();
  console.log("drop true");
}, true);

次のコード(@ digital-planeの回答に基づく)を使用すると、ページはドラッグターゲットになり、オブジェクトの埋め込みがイベントをキャプチャするのを防ぎ、画像を読み込みます。

document.body.addEventListener("dragover", function(e){
  e = e || event;
  e.preventDefault();
  console.log("over true");
}, true);

document.body.addEventListener("drop",function(e){
  e = e || event;
  e.preventDefault();
  console.log("Drop true");

  // begin loading image data to pass to our embed
  var droppedFiles = e.dataTransfer.files;
  var fileReaders = {};
  var files = {};
  var reader;

  for (var i = 0; i < droppedFiles.length; i++) {
    files[i] = droppedFiles[i]; // bc file is ref is overwritten
    console.log("File: " + files[i].name + " " + files[i].size);
    reader = new FileReader();
    reader.file = files[i]; // bc loadend event has no file ref

    reader.addEventListener("loadend", function (ev, loadedFile) {
      var fileObject = {};
      var currentReader = ev.target;

      loadedFile = currentReader.file;
      console.log("File loaded:" + loadedFile.name);
      fileObject.dataURI = currentReader.result;
      fileObject.name = loadedFile.name;
      fileObject.type = loadedFile.type;
      // call function on embed and pass file object
    });

    reader.readAsDataURL(files[i]);
  }

}, true);

Mac上のFirefoxでテスト済み。

0
1.21 gigawatts