web-dev-qa-db-fra.com

Empêcher le navigateur de charger un fichier glissé-déposé

J'ajoute un uploader html5 sur ma page.

Lorsqu'un fichier est déposé dans la zone de téléchargement, tout fonctionne parfaitement.

Toutefois, si je supprime accidentellement le fichier en dehors de la zone de téléchargement, le navigateur charge le fichier local comme s'il s'agissait d'une nouvelle page.

Comment puis-je prévenir ce comportement?

Merci!

151
Travis

Vous pouvez ajouter un écouteur d'événement à la fenêtre qui appelle preventDefault() sur tous les événements glisser-déplacer et déposer.
Exemple:

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

Après beaucoup de manipulations, j'ai trouvé que c'était la solution la plus stable:

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>

Si vous définissez effectAllow et dropEffect inconditionnellement dans la fenêtre, ma zone de dépôt n'accepte plus aucun d-n-d, que les propriétés soient définies ou non.

26
Axel Amthor

Pour autoriser le glisser-déposer uniquement sur certains éléments, vous pouvez effectuer les opérations suivantes:

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

Pour jQuery, la réponse correcte sera:

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

Ici, return false se comportera comme event.preventDefault() et event.stopPropagation().

7
VisioN

essaye ça:

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

Empêcher toutes les opérations de glisser-déposer par défaut peut ne pas être ce que vous souhaitez. Il est possible de vérifier si la source du glissement est un fichier externe, du moins dans certains navigateurs. J'ai inclus une fonction pour vérifier si la source de glissement est un fichier externe dans cette réponse StackOverflow

En modifiant la réponse de Digital Plane, vous pourriez faire quelque chose comme ceci: 

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

Pour construire sur la méthode "vérifier la cible" décrite dans quelques autres réponses, voici une méthode plus générique/fonctionnelle:

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

Appelé comme:

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

J'utilise un sélecteur de classe pour plusieurs zones de téléchargement afin que ma solution prenne cette forme moins pure

Basé sur la réponse d'Axel Amthor, avec dépendance à jQuery (alias à $)

_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

J'ai un HTML object (embed) qui remplit la largeur et la hauteur de la page. La réponse de @ digital-plane fonctionne sur les pages Web normales, mais pas si l'utilisateur passe sur un objet incorporé. J'ai donc eu besoin d'une solution différente. 

Si nous passons à la phase de capture event , nous pouvons obtenir les événements avant que l'objet incorporé les reçoive (notez la valeur true à la fin de l'appel du programme d'écoute des événements): 

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

En utilisant le code suivant (basé sur la réponse de @ digital-plane), la page devient une cible de glissement, elle empêche les objets incorporés de capturer les événements, puis charge nos images: 

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

Testé sur Firefox sur Mac. 

0
1.21 gigawatts