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!
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);
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.
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);
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()
.
essaye ça:
document.body.addEventListener('drop', function(e) {
e.preventDefault();
}, false);
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);
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])
);
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);
});
},
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.