2011-03-20 28 views
13

Estoy haciendo un uso extensivo del arrastre nativo de HTML5 &, y se comporta casi por completo, con una pequeña excepción.Comportamiento de arrastrar y soltar HTML5

Estoy tratando de resaltar mis zonas de gota cuando algo se arrastra sobre la página. Originalmente trató de lograr esto poniendo oyentes jQuery en el cuerpo del documento, así:

$("body").live('dragover',function(event){lightdz(event)}); 
$("body").live('dragexit dragleave drop',function(event){dimdz(event)}); 

con lightdz() y dimdz() cambiando la propiedad de estilo background-color de todas las zonas de saltos en la página para hacer que se fuera. Esto no funcionó. Cada vez que un objeto arrastrado ingresaba un elemento secundario en la página (como un contenedor div), el oyente lo marcaba como un evento dragleave y atenuaba las zonas de lanzamiento.

Lo solucioné aplicando el oyente a todos los elementos visibles de la página, en lugar de solo al cuerpo. Hubo ocasionalmente un leve parpadeo visible en las zonas de caída cuando cruzó el límite entre un elemento y otro, pero se veía bien.

De todos modos, ahora he cambiado lightdz() y dimdz() para que apliquen una animación jQuery fadeTo() rápida a todas las zonas que no sean dropzones. Esto se ve impresionante cuando funciona, y hace que sea muy evidente para el usuario lo que pueden y no pueden soltar cosas. El problema es que cuando pasa entre los límites del elemento, aplica la animación de desvanecimiento. Esto es mucho más aparente que el parpadeo ocasional del color de fondo, especialmente dado que si el objeto se arrastra sobre múltiples límites muy rápidamente, pondrá en cola las animaciones y hará que la página se desvanezca y entre en repetidas ocasiones.

Incluso si no me molesto con la animación fadeTo(), y simplemente cambio la opacidad, es mucho más visible que el parpadeo de color de fondo, porque toda la página cambia en lugar de solo los elementos de la zona de caída.

¿Hay alguna manera de hacer referencia a toda la página como un elemento único a los efectos de los eventos dragover y dragleave? En su defecto, ¿hay alguna manera de detectar una caída que tiene lugar fuera de la ventana del navegador? Si omito el evento dragleave, se ve bien, pero si se arrastra cualquier objeto sobre la ventana del navegador y luego se cae fuera de él, toda la página permanece desteñida.

Respuesta

13

Estoy realmente avergonzado de lo fácil que fue este.

$("*:visible").live('dragenter dragover',function(event){lightdz(event)}); 

$("#page").live('dragleave dragexit',function(event) 
{ 
    if(event.pageX == "0") 
     dimdz(event); 
}); 

$("*:visible").live('drop',function(event){dimdz(event)}); 

#page es un contenedor de toda la página. Si el evento dragleave toma el objeto arrastrado fuera de la ventana del navegador, event.pageX tendrá un valor de 0. Si ocurre en cualquier otro lugar, tendrá un valor distinto de cero.

+1

parece al menos en algunos navegadores, es event.originalEvent.pageX y no event.pageX ... –

+0

no funciona en opera y firefox para mí –

+0

'.live' está privado .. use' .on' en su lugar http : //api.jquery.com/live/ – Lipis

2

que puede ser conseguir excesivamente compleja aquí, pero me gustaría hacer algo como esto:

var draggingFile = false; 
var event2; 

//elements with the class hotspots are OK 
var hotspots = $(".hotspots"); 

//Handlers on the body for drag start & stop 
$("body").live("dragover", function(event){ draggingFile = true; event2 = event; }); 
$("body").live("dragexit dragleave drop", function(event){ draggingFile = false; event2 = event; }); 

//Function checks to see if file is being dragged over an OK hotspot regardless of other elements infront 
var isTargetOK = function(x, y){ 
    hotspots.each(function(i, el){ 
     el2 = $(el); 
     var pos = el2.offset(); 
     if(x => pos.left && x <= pos.left+el2.width() && y => pos.top && y <= post.top+el2.height()){ 
      return true; 
     } 
    }); 
    return false; 
}; 

//Mousemove handler on body 
$("body").mousemove(function(e){ 
    //if user is dragging a file 
    if(draggingFile){ 
     //Check to see if this is an OK element with mouse X & Y 
     if(isOKTarget(e.pageX, e.pageY)){ 
      //Light em' up! 
      lightdz(event2); 
     } else { /* Fade em' :(*/ dimdz(event2); } 
    } else { 
     dimdz(); //Having no parematers means just makes sure hotspots are off 
    } 
}); 

Por cierto que probablemente no va a trabajar inmediatamente el palo, por lo que tendrá que ajustar un poco para trabajar con tu código

+0

De hecho, me he dado cuenta de algo un poco buggy con fadeTo(). El desvanecimiento de la opacidad completa a la parcial de un evento relacionado con arrastrar o soltar parece suceder de forma instantánea, pero el desvanecimiento al revés parece tener unos segundos de anticipación. Está sucediendo en todas mis páginas, por lo que podría ser idiosincrásico para mi script, pero he decidido cambiar la opacidad como un cambio directo de CSS en lugar de animarlo. No se ve tan limpio, pero funciona, y también hace que mi pregunta original sea redundante. –

+0

Deseche esa declaración. Todavía tengo el problema en Chrome. Firefox maneja el cambio CSS sin problemas, pero Chrome parpadea sobre cada cambio de frontera. Veré si algo como esto funciona. –

1

Intenté la solución aceptada aquí, pero terminé usando setTimeout para solucionar el problema. Estaba teniendo un montón de problemas con el contenedor de toda la página bloqueando el elemento de caída si se flotaba en la parte superior, y sigue causando el problema si era el elemento de caída.

<body style="border: 1px solid black;"> 
    <div id="d0" style="border: 1px solid black;">&nbsp;</div> 
    <div id="d1" style="border: 1px solid black; display: none; background-color: red;">-&gt; drop here &lt;-</div> 
    <div id="d2" style="border: 1px solid black;">&nbsp;</div> 
    <div style="float: left;">other element</div> 
    <div style="float: left;">&nbsp;-&nbsp;</div> 
    <div style="float: left;">another element</div> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
</body> 
<script type="text/javascript"> 
    var resetTimer; 

    var f = function(e) 
    { 
     if (e.type == "dragover") 
     { 
      e.stopPropagation(); 
      e.preventDefault(); 
      if (resetTimer) 
      { 
       clearTimeout(resetTimer); 
      } 
      document.getElementById('d1').style.display = ''; 
     } 
     else 
     { 
      var f = function() 
      { 
       document.getElementById('d1').style.display = 'none'; 
      }; 
      resetTimer = window.setTimeout(f, 25); 
     } 
    }; 

    document.body.addEventListener("dragover", f, true); 
    document.body.addEventListener("dragleave", f, true); 
    document.getElementById('d1').addEventListener("drop", function(e){ f(); alert('dropped'); }, false); 
</script> 

Si se va a llamar simplemente f(); en lugar de window.setTimeout(f, 250);, verá algo de parpadeo desagradable del elemento de mostrar y ocultar.

http://jsfiddle.net/guYWx/

+0

El parpadeo se debe a que dispara un dragleave en BODY cuando ingresa a la zona de caída, lo que hace que la zona de caída desaparezca, lo que provoca la dragover nuevamente. Creo que lo solucioné (mi proyecto fue hace ocho o nueve meses, así que no puedo recordar todos los detalles) al aplicar el oyente dragover a todos los elementos de bloque visibles en la página. La suya es probablemente una solución mucho más elegante. –

+0

Si adjunta el detector de eventos al documento (en lugar del cuerpo), la dragover también se activa si el archivo se arrastra debajo del final del cuerpo. Esta solución no cubre arrastrar elementos en la página actual, vea también [esta pregunta] (http://stackoverflow.com/questions/6848043/how-do-i-detect-a-file-is-being-dragged-rather -than-a-draggable-element-on-my-pa/8494918 # 8494918). – bouke

Cuestiones relacionadas