Visión general
Tengo la siguiente estructura HTML y he adjuntado los eventos dragenter
y dragleave
al <div id="dropzone">
elemento.
<div id="dropzone">
<div id="dropzone-content">
<div id="drag-n-drop">
<div class="text">this is some text</div>
<div class="text">this is a container with text and images</div>
</div>
</div>
</div>
Problema
Cuando arrastro un archivo sobre <div id="dropzone">
, el dragenter
evento se dispara como se esperaba. Sin embargo, cuando muevo el mouse sobre un elemento secundario, como <div id="drag-n-drop">
, el dragenter
evento se activa para el <div id="drag-n-drop">
elemento y luego el dragleave
evento se activa para el <div id="dropzone">
elemento.
Si vuelvo a pasar el cursor sobre el <div id="dropzone">
elemento nuevamente, el dragenter
evento se activa nuevamente, lo cual es genial, pero luego el dragleave
evento se activa para el elemento secundario que acaba de salir, por lo removeClass
que se ejecuta la instrucción, que no es genial.
Este comportamiento es problemático por 2 razones:
Solo estoy adjuntando
dragenter
ydragleave
al,<div id="dropzone">
así que no entiendo por qué los elementos secundarios también tienen estos eventos adjuntos.¡Todavía estoy arrastrando sobre el
<div id="dropzone">
elemento mientras se cierne sobre sus hijos, así que no quierodragleave
disparar!
jsFiddle
Aquí hay un jsFiddle para jugar: http://jsfiddle.net/yYF3S/2/
Pregunta
Entonces ... ¿cómo puedo hacerlo de tal manera que cuando estoy arrastrando un archivo sobre el <div id="dropzone">
elemento, dragleave
no se dispara incluso si estoy arrastrando sobre cualquier elemento secundario ... solo debería dispararse cuando salgo del <div id="dropzone">
elemento ... Al desplazarse / arrastrarse por cualquier lugar dentro de los límites del elemento no se debe activar el dragleave
evento.
Necesito que esto sea compatible con varios navegadores, al menos en los navegadores que admiten arrastrar y soltar HTML5, por lo que esta respuesta no es adecuada.
Parece que Google y Dropbox han resuelto esto, pero su código fuente es reducido / complejo, por lo que no he podido resolverlo a partir de su implementación.
e.stopPropagation();
Respuestas:
Si no necesita vincular eventos a los elementos secundarios, siempre puede usar la propiedad puntero-eventos.
fuente
:hover
estilos separados o controladores de eventos de clic). En caso de que quiera preservar esos eventos, aquí hay otra solución que he estado usando: bensmithett.github.io/dragster.dropzone * {pointer-events: none;}
$('.element').addClass('dragging-over')
al elemento que está arrastrando y$('.element').removeClass('dragging-over')
cuando lo arrastra. Luego en tu CSS puedes tener.element.dragging-over * { pointer-events: none; }
. Eso elimina los eventos de puntero de todos los elementos secundarios solo cuando se arrastra.Finalmente encontré una solución con la que estoy contento. En realidad, encontré varias formas de hacer lo que quiero, pero ninguna fue tan exitosa como la solución actual ... en una solución, experimenté parpadeos frecuentes como resultado de agregar / eliminar un borde al
#dropzone
elemento ... en otra, el borde nunca se eliminó si te alejas del navegador.De todos modos, mi mejor solución hacky es esta:
Esto funciona bastante bien, pero surgieron problemas en Firefox porque Firefox estaba
dragenter
haciendo doble invocación, así que mi contador estaba apagado. Pero, sin embargo, no es una solución muy elegante.Luego me topé con esta pregunta: cómo detectar el evento dragleave en Firefox al arrastrar fuera de la ventana
Entonces tomé la respuesta y la apliqué a mi situación:
Esto es limpio y elegante y parece estar funcionando en todos los navegadores que he probado hasta ahora (aún no he probado IE).
fuente
stopPropagation()
ypreventDefault()
se prefiere. Yo soltaría elreturn false
.¡Esto es un poco feo pero funciona maldita sea! ...
En su controlador 'dragenter' almacene el event.target (en una variable dentro de su cierre, o lo que sea), luego en su controlador 'dragleave' solo active su código si event.target === el que almacenó.
Si su 'dragenter' está disparando cuando no lo desea (es decir, cuando ingresa después de dejar elementos secundarios), entonces la última vez que se dispara antes de que el mouse abandone al padre, está en el padre, por lo que el padre siempre estará el 'grageador' final antes del 'dragleave' previsto.
fuente
Al principio, acepté que la gente descartara el
pointer-events: none
enfoque. Pero luego me pregunté:En mi caso, tengo muchas cosas que suceden en los niños, por ejemplo, desplazar el mouse para mostrar botones para acciones adicionales, edición en línea, etc. Sin embargo, nada de eso es necesario o incluso deseado durante un arrastre.
En mi caso, uso algo como esto para desactivar selectivamente los eventos de puntero para todos los nodos secundarios del contenedor primario:
Use su enfoque favorito para agregar / eliminar la clase
dragging-in-progress
en los controladores de eventosdragEnter
/dragLeave
, como hice o hago lo mismo endragStart
et. Alabama.fuente
dragstart
evento y elimíneladragend
.Esto parece ser un error de Chrome.
La única solución que se me ocurrió fue crear un elemento de superposición transparente para capturar sus eventos: http://jsfiddle.net/yYF3S/10/
JS :
HTML :
fuente
El problema es que sus elementos dentro de las zonas de caída son, por supuesto, parte de la zona de caída y cuando ingresa a los elementos secundarios, deja a los padres. Resolver esto no es fácil. Puede intentar agregar eventos a los niños también agregando su clase nuevamente a los padres.
Sus eventos aún se dispararán varias veces, pero nadie lo verá.
// Editar: use el evento dragmove para sobrescribir permanentemente el evento dragleave:
Defina el evento dragleave solo para la zona de caída.
fuente
dragleave
... cuando dejo a un niño, aún podría estar dentro de los padres,#dropzone
pero eso no volverá a desencadenar eldragenter
evento :(dragleave
evento para el elemento hijo que acaba de salir, por lo que nuevamenteremoveClass
se ejecuta la instruccióndragleave
solo para el#dropzone
... si pudiera, no tendría este problema.Como se menciona en esta respuesta , puede evitar que los nodos secundarios se activen en eventos, pero si necesita vincular algunos eventos, haga lo siguiente:
Y agregue este a su código JS:
fuente
Si está utilizando jQuery, consulte esto: https://github.com/dancork/jquery.event.dragout
Es realmente asombroso.
EDITAR: en realidad, no creo que dependa de jQuery, probablemente pueda usar el código incluso sin él.
fuente
dragleave
secundarios activados a pesar de que no he salido de la zona de caída principal.dragout
fue la única solución que funcionó para mí.@hristo Tengo una solución mucho más elegante. Comprueba que si eso es algo que podrías usar.
Su esfuerzo no fue malgastado después de todo. Al principio pude usar el tuyo, pero tuve diferentes problemas en FF, Chrome. Después de pasar tantas horas, recibí esa sugerencia funcionando exactamente como estaba previsto.
Así es como es la implementación. También aproveché las señales visuales para guiar correctamente a los usuarios sobre la zona de colocación.
fuente
var dropZoneHideDelay=70, dropZoneVisible=true;
dropZoneHideDelay, dropZoneVisible
son necesarios en dos'on'
eventos de documentos en mi implementación.Mis dos centavos: esconde una capa sobre tu zona de caída y luego muéstrala cuando grabas en el centro, y apunta al dragleave sobre ella.
Demostración: https://jsfiddle.net/t6q4shat/
HTML
CSS
JS
fuente
Entonces, para mí, el enfoque
pointer-events: none;
no funcionó demasiado bien ... Así que aquí está mi solución alternativa:De esta manera no es posible
dragleave
el elemento primario (en un elemento secundario) odragover
un elemento secundario. espero que esto ayude :)* La clase '.active' agrego cuando
dragenter
odragleave
. Pero si está trabajando sin eso, simplemente deje la clase ausente.fuente
Solución rápida súper simple para esto, no se ha probado exhaustivamente pero funciona en Chrome en este momento.
Disculpe el Coffeescript.
Esto soluciona el error de parpadeo de Chrome, o al menos la permutación que me causaba problemas.
fuente
Esta respuesta se puede encontrar aquí:
Se activa el dragleave HTML5 al pasar el cursor sobre un elemento secundario
fuente
Mi version:
Con este diseño:
He hecho un vaciado de las clases de elementos para
e.target
,e.currentTarget
,e.relatedTarget
para ambosdragover
ydragleave
eventos.Me demostró que al dejar el bloque padre (
.dropzone
)e.relatedTarget
no es un hijo de este bloque, así que sé que estoy fuera de la zona de caída.fuente
Aquí, una de las soluciones más simples ● ︿ ●
Eche un vistazo a este violín <- intente arrastrar algún archivo dentro del cuadro
Puedes hacer algo como esto:
Por eso ya deberías saber lo que está sucediendo aquí.
Solo echa un vistazo al violín, ya sabes.
fuente
He tenido un problema similar y lo solucioné de esta manera:
El problema: la función drop (ev) se activa cuando el usuario coloca un elemento en la "zona drop" (elemento ul), pero, desafortunadamente, también cuando el elemento se cae en uno de sus elementos secundarios (elementos li).
La solución:
fuente
Intenté implementar esto yo mismo para un cuadro de carga de archivos donde el color del cuadro cambiaría cuando los usuarios arrastraran un archivo al espacio.
Encontré una solución que es una buena combinación de Javascript y CSS. Digamos que tiene una zona desplegable
div
con id#drop
. Agregue esto a su Javascript:Luego, agregue esto a su CSS, para inactivar todos los niños clasificarán
.inactive
:Por lo tanto, los elementos secundarios estarán inactivos mientras el usuario arrastre el elemento sobre el cuadro.
fuente
No me sentí satisfecho con ninguna de las soluciones presentadas aquí, porque no quiero perder el control sobre los elementos secundarios.
Así que he usado un enfoque lógico diferente, traduciéndolo en un complemento jQuery, llamado jquery-draghandler . No manipula absolutamente el DOM, garantizando altas prestaciones. Su uso es simple:
Aborda perfectamente el problema sin comprometer ninguna funcionalidad DOM.
Descarga, detalles y explicaciones en su repositorio Git .
fuente
frame
sy tu elemento está en el límite. En ese caso, no sugiero este enfoque.De hecho, me gusta lo que veo en https://github.com/lolmaus/jquery.dragbetter/pero quería compartir una posible alternativa. Mi estrategia general era aplicar un estilo de fondo a la zona de caída (no a sus elementos secundarios) cuando la graficaba a ella o a cualquier elemento secundario (mediante burbujeo). Luego elimino el estilo al dragleaving la zona de caída. La idea era cuando me mudaba a un niño, incluso si elimino el estilo de la zona de caída cuando lo dejo (los fuegos de dragleave), simplemente volvería a aplicar el estilo a la zona de caída principal al ingresar a cualquier niño. El problema es, por supuesto, que cuando me muevo de la zona de caída a un niño de la zona de caída, la gragera se dispara sobre el niño antes de la caída del dragle, por lo que mis estilos se aplicaron fuera de orden. La solución para mí fue usar un temporizador para forzar el evento dragenter de nuevo a la cola de mensajes, lo que me permitió procesarlo DESPUÉS de la secuencia de descarga. Usé un cierre para acceder al evento en la devolución de llamada del temporizador.
Esto parece funcionar en Chrome, es decir, Firefox y funciona independientemente de la cantidad de niños en la zona de caída. Estoy un poco incómodo con el tiempo de espera que garantiza la secuenciación de eventos, pero parece funcionar bastante bien para mi caso de uso.
fuente
Estaba tratando de implementar esto yo mismo, y tampoco quería Jquery ni ningún complemento.
Quería manejar la carga del archivo, de la siguiente manera me pareció mejor:
Estructura de archivos:
--- / uploads {directorio de cargas}
--- /js/slyupload.js {archivo javascript}
--- index.php
--- upload.php
--- styles.css {solo un poco de estilo ..}
Código HTML:
Entonces este es el archivo Javascript adjunto :: 'js / slyupload.js'
CSS:
fuente
Lo siento, es javascript, no jquery, pero para mí es la forma más lógica de resolverlo. El navegador debe llamar a dropleave (del elemento anterior) antes de dropenter (ofr the new element, ya que algo no puede ingresar a otra cosa antes de dejar lo primero, ¡no entiendo por qué lo hicieron! Así que solo necesita retrasar de dropleave así:
Y el dropenter ocurrirá después del dropleave, ¡eso es todo!
fuente
Utilice el
greedy : true
para el niño como una función dedroppable
. Luego, inicie solo el evento en el que se hizo clic en la primera capa.fuente