2012-01-21 20 views
12

Desidero sovrapporre un div al viewport quando l'utente trascina un file nella finestra.Eventi di propagazione, sovrapposizione e trascinamento della selezione

Tuttavia, ho problemi con la propagazione dell'evento. Quando imposto l'overlay su display: block, sembra che venga generato un evento dragleave e poi un altro dragenter e quindi un altro dragleave di nuovo, quindi è sempre in stato post-trascinamento. Chiaramente chiamo e.stopPropagation() e e.preventDefault() sull'oggetto evento, ma non sembra fare la differenza.

L'uscita console.log() quando si trascina qualcosa sulla finestra:

dragenter 
dragenter 
dragleave 
dragenter 
dragleave 

il CSS. #overlay è impostato su display: none di default, ma mostrerà se body ha la classe 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; 
    } 

Il javascript. Aggiungere la classe 'DragEnter' sul DragEnter e lo rimuove il 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'); 
}); 

il codice HTML:

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

risposta

1

Grazie a Scottux, che mi ha portato sulla strada giusta.

L'unico problema era che copriva anche il resto della pagina, quindi nessuno degli elementi o degli input era cliccabile. Ho dovuto nascondere #dragOverlay di default con "display: none" e visualizzarla su questo evento

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

Impressionante, esattamente il problema che cercavo di risolvere da un paio d'ore;) ma per quanto ne so jquery, $ ('*: visible'). Live() deve essere un selettore piuttosto costoso. potrebbe esserci un'altra soluzione? Intendo i ragazzi di imgur.com ovviamente trovato un modo (trascina un file dal tuo finder/explorer sul sito e vedrai) ma non ho potuto decodificare il codice per scoprire come lo hanno fatto :( –

+0

Penso che sia una soluzione piuttosto pesante inoltre, ma è il più semplice che trovo (con limiti di tempo su un progetto di lavoro e tutti). Ho provato anche a guardare il codice imgur e non è qualcosa che volevo approfondire. – twig

5

proprio overlay occupa la dimensione intero documento, quando si trascina in, si riempie il suo spazio e il tuo mouse viene effettivamente estratto dal corpo e ora si trova sopra la sovrapposizione. Questo innesca un ciclo di mouseleave/mouseenter. Per ottenere ciò che stai cercando, puoi associare l'evento a una sovrapposizione trasparente con un alto indice z rispetto alla sovrapposizione visibile che ha un indice z inferiore. Ciò manterrebbe l'evento nell'elemento più alto.

Esempio:

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

+0

esempio perfetto, quindi grazie. – Kate

+0

Questo è il modo di fare! – BastienSander

0

La soluzione più semplice è invece di utilizzare DragEnter uso dragover

DragOver Questo l'evento viene attivato quando il mouse viene spostato su un elemento quando si verifica un trascinamento. La maggior parte delle volte, l'operazione che si verifica durante un listener sarà uguale all'evento dragenter.

+0

Tranne che non è possibile rilevare quando lascia la zona di rilascio – cdmckay

+0

Questo fa sì che il codice modifichi ripetutamente la visibilità della sovrapposizione, il che può (o non può) avere conseguenze sulle prestazioni – 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

Potresti spiegare la tua risposta? Inviare codice senza elaborare può confondere gli altri con lo stesso numero – Seth

+0

Questo ha sicuramente bisogno di qualche chiarimento – ouflak

+0

im usando questo codice per mostrare la zona di rilascio quando il mouse sta entrando nella finestra dr agging un file. l'oggetto ha una proprietà .eTimestamp che contiene event.timeStamp e im che verifica se ci sono almeno 300ms tra entrambi gli eventi per prevenire l'attivazione multipla (ho avuto quel problema) –

Problemi correlati