javascript - Toda la página como zona de arrastre para arrastrar y soltar
css drag-and-drop (1)
El truco consiste en utilizar una zona de colocación que cubra toda la página y almacenar en caché el target
de window.ondragenter
para comparar con el target
de window.ondragleave
.
Primero, la zona de caída:
<style>
div.dropzone
{
/* positions to point 0,0 - required for z-index */
position: fixed; top: 0; left: 0;
/* above all elements, even if z-index is used elsewhere
it can be lowered as needed, but this value surpasses
all elements when used on YouTube for example. */
z-index: 9999999999;
/* takes up 100% of page */
width: 100%; height: 100%;
/* dim the page with 50% black background when visible */
background-color: rgba(0,0,0,0.5);
/* a nice fade effect, visibility toggles after 175ms, opacity will animate for 175ms. note display:none cannot be animated. */
transition: visibility 175ms, opacity 175ms;
}
</style>
<!-- both visibility:hidden and display:none can be used,
but the former can be used in CSS animations -->
<div style="visibility:hidden; opacity:0" class="dropzone"></div>
A pesar de que la zona de colocación cubrirá toda la página, se utilizará visibility:hidden
o display:none
ocultará de la vista. Utilicé la visibility:hidden
para que las animaciones CSS puedan usarse para animar la transición.
Asignando los eventos.
<script>
/* lastTarget is set first on dragenter, then
compared with during dragleave. */
var lastTarget = null;
window.addEventListener("dragenter", function(e)
{
lastTarget = e.target; // cache the last target here
// unhide our dropzone overlay
document.querySelector(".dropzone").style.visibility = "";
document.querySelector(".dropzone").style.opacity = 1;
});
window.addEventListener("dragleave", function(e)
{
// this is the magic part. when leaving the window,
// e.target happens to be exactly what we want: what we cached
// at the start, the dropzone we dragged into.
// so..if dragleave target matches our cache, we hide the dropzone.
if(e.target === lastTarget || e.target === document)
{
document.querySelector(".dropzone").style.visibility = "hidden";
document.querySelector(".dropzone").style.opacity = 0;
}
});
</script>
Así que aquí está el proceso: arrastra un archivo sobre la ventana y window.ondragenter se dispara inmediatamente. El target
se establece en el elemento raíz, <html>
. Entonces, inmediatamente se muestra su zona de caída, que cubre toda la página. window.ondragenter
se disparará de nuevo, esta vez el objetivo será tu zona de caída. Cada vez que se dragenter
evento dragenter
, almacenará en caché el objetivo, ya que este será el objetivo que coincidirá con el último evento window.ondragleave
que se dispara cuando se arrastra fuera de la ventana.
¿Por qué funciona esto? No tengo idea, pero así es como se hace. Este es prácticamente el único método de trabajo que se activa cuando el usuario arrastra la página.
Creo que funciona porque una vez que la zona de caída no está oculta, siempre será el último objetivo. Cubre cada píxel de la página, incluso la etiqueta <html>
. Este método se basa en la activación de hojas de arrastre al salir de la ventana. Desafortunadamente, hay un error en Firefox que impide que funcione correctamente. Por favor, vote por él para que se arregle más pronto . A partir de Firefox 57.0.2, el dragleave parece disparar correctamente. Sin embargo, se requiere una solución, verificando el document
lugar del elemento en caché:
if(e.target === lastTarget || e.target === document)
Aquí hay un JSBin de eso en acción . Probado en las últimas versiones de Chrome, Firefox, Edge e IE11.
Mientras escribía aplicaciones web que tomaban entrada de archivos, quería usar arrastrar y soltar, pero no quería solo una pequeña zona de descarga en la página. Pensé que sería más conveniente si pudiera dejarlo en cualquier lugar de la página. Afortunadamente, el evento window.ondrop se dispara en cualquier lugar de la página, pero quería un efecto elegante para mostrar al usuario visualmente que era posible arrastrar y soltar.
Para hacerlo, todo lo que se necesitaba era detectar cuándo se arrastraba un archivo a la ventana , y cuando se arrastraba , para activar un efecto que mostraba al usuario que la aplicación estaba habilitada para arrastrar. Resulta que los eventos de arrastre no son tan convenientes. Supuse que window.ondragenter
solo se activaría una vez, cuando el usuario ingresara a la página. Luego, cuando dejaste la ventana, window.ondragleave
la ventana. Incorrecto. Se dispara constantemente a medida que el mouse se mueve sobre elementos secundarios en la página.
Miré qué propiedades estaban disponibles en el objeto de evento, tratando de encontrar algo que pudiera aislar lo que necesitaba, pero nada funcionó. Lo más que conseguí fue poder cambiar el color de fondo del body
. Y solo si no había nada más en la página.
Toneladas de sitios de carga de archivos lo hicieron bien. Imgur y WeTransfer, por ejemplo. Sus sitios estaban todos codificados en spahetti y comprimidos hasta el punto de la ilegibilidad, y no pude encontrar nada sobre el tema buscando en Google.
Entonces, ¿cómo se puede hacer esto?