2012-01-21 20 views
12

Quiero superponer un div sobre la ventana gráfica cuando el usuario arrastra un archivo a la ventana.Eventos de propagación de eventos, superposición y arrastrar y colocar

Sin embargo, tengo problemas con la propagación del evento. Cuando configuro la superposición en display: block, parece disparar un evento dragleave y luego otro dragenter y luego otro nuevamente, por lo que siempre está en un estado posterior a la dragleave. Por supuesto, llamo al e.stopPropagation() y al e.preventDefault() en el objeto del evento, pero no parece marcar la diferencia.

El console.log() de salida cuando se arrastra algo sobre la ventana:

dragenter 
dragenter 
dragleave 
dragenter 
dragleave 

El css. #overlay se establece en display: none por defecto, pero se mostrará si tiene body la clase dragenter:

body { 
     position: absolute; 
     height: auto; 
     top: 0; 
     left: 0; 
     right: 0; 
     bottom: 0; 
     margin: 0; 
     padding: 0; 
    } 

    #overlay { 
     position: absolute;   
     height: auto; 
     width: auto; 
     top: 0; 
     left: 0; 
     right: 0; 
     bottom: 0; 
     background: url(bg.png) repeat-x top right, url(bg.png) repeat-x bottom left, url(bg.png) repeat-y top right, url(bg.p 
ng) repeat-y bottom left; 
     display: none; 
    } 

    body.dragenter #overlay { 
     display: block; 
    } 

El javascript. Agregue la clase 'dragenter' en dragenter y lo elimina en DragLeave:

$(document).on('dragenter', function (e) { 
    e.stopPropagation(); 
    e.preventDefault(); 
    console.log('dragenter'); 
    $(document.body).addClass('dragenter'); 
}); 

$(document).on('dragleave', function (e) { 
    e.stopPropagation(); 
    e.preventDefault(); 
    console.log('dragleave'; 
    $(document.body).removeClass('dragenter'); 
}); 

El html:

<body> 
<div id="overlay">...</div> 
...  
</body> 

Respuesta

1

Gracias a Scottux, que me llevó a la pista derecha.

El único problema fue que también cubrió el resto de la página, por lo que no se pudo hacer clic en ninguno de los elementos o entradas. Tenía que ocultar #dragOverlay por defecto con "display: none" y mostrarlo en este evento

// Display an overlay when dragging a file over 
$('*:visible').live('dragenter', function(e) { 
    e.stopPropagation(); 
    $('body').addClass('drag-enter'); 
}); 
+0

Impresionante, es exactamente el problema que estaba buscando resolver por un par de horas;) pero hasta donde sé jquery, $ ('*: visible'). Live() debe ser un selector bastante caro. ¿Podría haber otra solución? me refiero a los chicos de imgur.Com obviamente encontró una forma (arrastrar un archivo desde su buscador/explorador al sitio y verá) pero no pude revertir la ingeniería del código para descubrir cómo lo hicieron :( –

+0

Creo que es una solución bastante pesada también, pero es el más fácil que encuentro (con limitaciones de tiempo en un proyecto de trabajo y todo). Traté de ver el código imgur también y no es algo en lo que quería profundizar. – twig

5

Su superposición ocupa todo el tamaño del documento, cuando se arrastra adentro, que se llena su espacio y su mouse se saca efectivamente del cuerpo y ahora está sobre la superposición. Esto desencadena un bucle mouseleave/mouseenter. Para lograr lo que busca, puede vincular el evento a una superposición transparente con un alto índice z sobre la superposición visible que tiene un índice Z más bajo. Esto mantendría el evento en el elemento más alto.

Ejemplo:

http://jsfiddle.net/scottux/z7yaB/

+0

ejemplo perfecto, así que gracias. – Kate

+0

¡Esta es la manera de hacerlo! – BastienSander

0

La solución es sencilla en lugar de utilizar dragenter uso dragover

dragover Este El evento se activa cuando el mouse se mueve sobre un elemento cuando se produce un arrastre. La mayoría de las veces, la operación que ocurre durante un oyente será la misma que el evento dragenter.

+0

Excepto que no puede detectar cuando sale de la zona de colocación. – cdmckay

+0

Esto también hace que el código cambie la visibilidad de la superposición para disparar repetidamente, lo que puede (o no) tener consecuencias en el rendimiento. – ZachB

1
var dropZone = function() { 
     var self = this; 
     this.eTimestamp = 0; 
     this.showDropZone = function(e) { 
      e.stopPropagation(); 
      e.preventDefault(); 
      if (self.eTimestamp + 300 < e.timeStamp) { 
       $("#coverDropZone").show(); 
       self.eTimestamp = e.timeStamp; 
      } 
      return false; 
     } 
     this.hideDropZone = function(e) { 
      e.stopPropagation(); 
      e.preventDefault(); 
      if (self.eTimestamp + 300 < e.timeStamp) { 
       $("#coverDropZone").hide(); 
       self.eTimestamp = e.timeStamp; 
      } 
      return false; 
     } 
     this.showImage = function(e) { 
      e.stopPropagation(); 
      e.preventDefault(); 
      console.log(e); 
      return false; 
     } 
     document.addEventListener('dragenter', self.showDropZone, false); 
     document.addEventListener('dragleave', self.hideDropZone, false); 
     document.addEventListener('drop', self.showImage, false); 
    } 
+2

¿Podría explicar su respuesta? Publicar el código sin elaboración puede confundir a otros con el mismo problema. – Seth

+0

Esto definitivamente necesita alguna aclaración. – ouflak

+0

im usando este código para mostrar la zona de soltar cuando el mouse está entrando en la ventana dr agging un archivo. el objeto tiene una propiedad .eTimestamp que contiene el evento.timeStamp y estoy comprobando si hay al menos 300 ms entre ambos eventos para evitar disparos múltiples (tuve ese problema) –

Cuestiones relacionadas