webentwicklung-frage-antwort-db.com.de

Verhindern, dass der Browser eine Drag & Drop-Datei lädt

Ich füge meiner Seite einen html5 Drag & Drop-Uploader hinzu.

Wenn eine Datei im Upload-Bereich abgelegt wird, funktioniert alles bestens.

Wenn ich jedoch die Datei versehentlich außerhalb des Upload-Bereichs ablege, lädt der Browser die lokale Datei, als wäre es eine neue Seite.

Wie kann ich dieses Verhalten verhindern?

Vielen Dank!

151
Travis

Sie können dem Fenster einen Ereignis-Listener hinzufügen, der preventDefault() für alle Dragover- und Drop-Ereignisse aufruft.
Beispiel:

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

Nachdem ich viel herumgespielt hatte, fand ich das die stabilste Lösung:

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>

Wenn Sie sowohl effectAllow als auch dropEffect im Fenster unbedingt festgelegt haben, akzeptiert meine Drop-Zone kein d-n-d mehr, unabhängig davon, ob die Eigenschaften neu festgelegt sind oder nicht.

26
Axel Amthor

Um das Ziehen und Ablegen nur für einige Elemente zuzulassen, können Sie Folgendes tun:

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

Für jQuery lautet die richtige Antwort:

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

Hier verhält sich return false wie event.preventDefault() und event.stopPropagation().

7
VisioN

versuche dies:

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

Standardmäßig zu verhindern, dass alle Drag & Drop-Vorgänge ausgeführt werden, ist möglicherweise nicht das, was Sie möchten. Es kann überprüft werden, ob es sich bei der Ziehquelle um eine externe Datei handelt, zumindest in einigen Browsern. Ich habe eine Funktion hinzugefügt, um zu überprüfen, ob die Ziehquelle eine externe Datei in dieser StackOverflow-Antwort ist. 

Wenn Sie die Antwort von Digital Plane ändern, können Sie Folgendes tun: 

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

Um auf die "check the target" -Methode zu bauen, die in einigen anderen Antworten beschrieben wird, folgt eine allgemeinere/funktionellere Methode:

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

Genannt wie:

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

Ich verwende einen Klassenselektor für mehrere Uploadbereiche, so dass meine Lösung diese weniger reine Form hatte

Basierend auf der Antwort von Axel Amthor mit Abhängigkeit von jQuery (Alias ​​auf $)

_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

Ich habe ein HTML object (embed), das die Breite und Höhe der Seite ausfüllt. Die Antwort von @ Digital-Plane funktioniert auf normalen Webseiten, jedoch nicht, wenn der Benutzer auf ein eingebettetes Objekt fällt. Ich brauchte also eine andere Lösung. 

Wenn Sie zu event capture phase wechseln, können Sie die Ereignisse abrufen, bevor das eingebettete Objekt sie empfängt (beachten Sie den true-Wert am Ende des Ereignislistener-Aufrufs): 

// 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);

Mit dem folgenden Code (basierend auf der Antwort von @ digital-plane) wird die Seite zu einem Ziehziel. Sie verhindert, dass Objekte die Ereignisse erfassen, und lädt dann unsere Bilder: 

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);

Getestet mit Firefox unter Mac. 

0
1.21 gigawatts