Il trucco è quello di utilizzare una zona di lancio che copre l'intera pagina, e la cache di target
window.ondragenter
da confrontare con il target
di window.ondragleave
.
In primo luogo, quello di lancio:
<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>
Anche se la zona di lancio sarà copre l'intera pagina, utilizzando visibility:hidden
o display:none
nasconderà alla vista. Ho usato visibility:hidden
in modo che le animazioni CSS possano essere utilizzate per animare la transizione.
Assegnazione degli eventi
<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>
Quindi, ecco il processo: È possibile trascinare un file sulla finestra, e window.ondragenter incendi immediatamente. target
è impostato sull'elemento principale, <html>
. A questo punto, viene immediatamente visualizzata la tua dropzone, che copre l'intera pagina. window.ondragenter
scatterà di nuovo, questa volta l'obiettivo sarà il tuo dropzone. Ogni volta che l'evento dragenter
si attiva, memorizza nella cache il target, poiché questo sarà il target che corrisponderà all'ultimo evento window.ondragleave
che viene generato quando si trascina fuori dalla finestra.
Perché funziona? Non ne ho idea, ma è così che si fa. Questo è praticamente l'unico metodo di lavoro che si attiva quando l'utente si allontana dalla pagina.
Credo che funzioni perché una volta che la casella di riepilogo non è nascosta, sarà sempre l' l'ultimo obiettivo. Copre ogni pixel della pagina, anche il tag <html>
. Questo metodo si basa sull'attivazione del trascinamento di dragleave quando si esce dalla finestra. Sfortunatamente c'è un bug in Firefox che impedisce il corretto funzionamento.Si prega di votare per questo sarà risolto prima. A partire da Firefox 57.0.2, il dragleave sembra funzionare correttamente. Tuttavia, è necessaria una soluzione, controllando document
invece che l'elemento memorizzato nella cache:
if(e.target === lastTarget || e.target === document)
Here's a JSBin of it in action. Testato nelle ultime versioni di Chrome, Firefox, Edge e IE11.
Questo non funziona in Firefox, in quanto il file event.target restituito da dragleave è HTML, che non corrisponde all'ultimo elemento memorizzato nella cache (molto probabilmente il .dropzone). –
@DannyLin Sfortunatamente c'è un [bug in Firefox] (https://bugzilla.mozilla.org/show_bug.cgi?id=656164) che impedisce il corretto funzionamento. Si prega di votare per esso in modo che verrà risolto prima. – bryc
Ah, quindi il bug sembra essere stato risolto ora? Firefox restituisce in modo affidabile 'document' come' event.target' quando lascia la finestra. Ho incluso questo workaround nella risposta. – bryc