2011-07-20 23 views
116

Estoy agregando una carga y descarga de html5 en mi página.Evitar que el navegador cargue un archivo de arrastrar y soltar

Cuando se deja caer un archivo en el área de carga, todo funciona muy bien.

Sin embargo, si accidentalmente coloco el archivo fuera del área de carga, el navegador carga el archivo local como si fuera una página nueva.

¿Cómo puedo evitar este comportamiento?

Gracias!

+1

Es curioso el código que está utilizando para manejar la carga de la función arrastrar/soltar html5. Gracias. – robertwbradford

Respuesta

193

Puede agregar un detector de eventos a la ventana que llama al preventDefault() en todos los eventos de dragover y drop.
Ejemplo:

window.addEventListener("dragover",function(e){ 
    e = e || event; 
    e.preventDefault(); 
},false); 
window.addEventListener("drop",function(e){ 
    e = e || event; 
    e.preventDefault(); 
},false); 
+18

dragover es la pieza que me faltaba. – cgatian

+3

Confirmo que se necesitan manejadores 'dragover' y' drop' para evitar que el navegador cargue el archivo caído. (Chrome más reciente, 08/08/2015). La solución también funciona en FF. – Offirmo

+1

Esto funciona perfectamente, y puedo confirmar que se puede usar en combinación con elementos de página que están configurados para aceptar eventos de inserción, como los de arrastrar y soltar archivos de carga de archivos como resumable.js. Es útil evitar el comportamiento predeterminado del navegador en los casos en que un usuario suelta accidentalmente un archivo que desea cargar fuera de la zona de colocación de carga de archivo real y luego se pregunta por qué ahora ve el mismo archivo representado directamente en la ventana del navegador (suponiendo que se ha eliminado un tipo de archivo compatible, como una imagen o un video), en lugar del comportamiento esperado al ver la carga de archivos. – bluebinary

1

probar esto:

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

La prevención de todas las operaciones de arrastrar y soltar de forma predeterminada podría no ser lo que quieres. Es posible verificar si el origen de arrastre es un archivo externo, al menos en algunos navegadores. He incluido una función para verificar si el origen de arrastre es un archivo externo en este StackOverflow answer. respuesta

Modificación digital del avión, que podría hacer algo como esto:

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

¿Cuál es el punto de 'e || evento; '? ¿Dónde se define 'evento'? No importa. Parece que es un objeto global en IE? Encontré esta cita, '" En Microsoft Visual Basic Scripting Edition (VBScript), debe acceder al objeto de evento a través del objeto de ventana ". [Aquí] (https://msdn.microsoft.com/en-us/library/ ms535863 (v = vs.85) .aspx) –

7

Para permitir sólo arrastrar y soltar en algunos elementos, se podría hacer algo como:

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

Después de una gran cantidad de volverse locos, me pareció que era la solución más estable:

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>

Ajuste de los dos effectAllow y dropEffect incondicionalmente en la ventana hace que mi zona de caída no aceptar ninguna d-n-d por más tiempo, sin tener en cuenta si las propiedades se establecen nuevos o no.

4

para jQuery la respuesta correcta será:

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

Aquí return false se comportará como event.preventDefault() y event.stopPropagation().

1

Para aprovechar el método de "comprobar el objetivo" esbozado en algunas otras respuestas, aquí es un método más genérico/funcional:

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

Llamado como:

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

tengo una HTML object (embed) que llena el ancho y alto de la página. La respuesta por @ digital-plan funciona en páginas web normales, pero no si el usuario cae en un objeto incrustado. Entonces necesitaba una solución diferente.

Si cambiamos a usar el event capture phase podemos obtener los eventos antes de que el objeto incrustado los recibe (nótese el valor true al final de la llamada detector de eventos):

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

Usando el siguiente código (basada en la respuesta de @ digitales plano) la página se convierte en un destino de arrastre, que evita que se incrusta objeto de capturar los eventos y luego carga nuestras imágenes:

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

probado en Firefox en Mac.

Cuestiones relacionadas