2012-11-01 9 views
22

Si consideri la seguente pagina Web:come catturare tutti gli eventi di scorrimento in una pagina senza associare un gestore onscroll ad ogni singolo contenitore

<html> 
    <body onscroll="alert('body scroll event')"> 
    <div style='width:200px;height:200px;overflow:auto' onscroll="alert('div scroll event')"> 
     <div style='height:400px'> 
     </div> 
    </div> 
    </body> 
</html> 

Questo html crea un div con una barra di scorrimento. Se sposti la barra di scorrimento, viene attivato l'evento "onscroll" sull'elemento div. Tuttavia, l'evento "onscroll" sul corpo NON viene attivato. Questo è previsto, dal momento che il W3C afferma che gli eventi onscroll dell'elemento non "bolla".

Tuttavia, sto sviluppando un framework Web sul lato client che deve sapere ogni volta che si scorre una barra di scorrimento su QUALSIASI elemento della pagina. Questo sarebbe facile da fare se bolle "onscroll", ma sfortunatamente no. C'è un altro modo per rilevare eventi onscroll su un'intera pagina? (In questo momento mi sto concentrando principalmente su Webkit, quindi una soluzione specifica per Webkit andrebbe bene ...)

Qui ci sono alcune cose che ho provato: 1. Catturare DOMAttrModified (non sembra sparare per barre di scorrimento in movimento.) 2. Utilizzo di osservatori DOM (anche non sembrano al fuoco per le barre di scorrimento) 3. Modifica del tipo "onscroll" evento a bollire (sembra non essere possibile)

Sembra che l'unico modo per catturare eventi onscroll a livello globale è quello di allegare un evento onscroll a OGNI elemento che può scorrere, che è molto brutto e danneggerà le prestazioni del mio framework.

Qualcuno conosce un modo migliore?

Grazie in anticipo!

+0

window.onscroll non ha funzionato? – JustinDanielson

risposta

7

* ... grilli ... *

OK, credo che questa domanda non sta andando per ottenere qualsiasi amore StackOverflow, quindi potrebbe anche rispondere alla mia domanda per quanto riguarda la soluzione migliore Ho trovato fino ad ora, nel caso in cui un altro utente si imbattesse in questa domanda:

La soluzione migliore che ho trovato è quella di acquisire "onmousedown" e "onkeydown" per l'elemento BODY: questi eventi bolla, e così se un utente tenta di spostare una barra di scorrimento sulla pagina, queste funzioni globali verranno attivate come sottoprodotto. Quindi, in queste funzioni, cerca semplicemente event.target e allega un evento temporaneo "onscroll" a quegli oggetti finché il mouse/tasto non è nuovamente "su". Usando questo metodo, puoi evitare "handler bloat" e comunque catturare globalmente tutti gli eventi "onscroll". (Penso che questo funzioni anche per lo scroll del mouse, ma la mia ricerca su quella ruga finale è ancora in sospeso.)

+0

Inoltre, è necessario aggiungere un evento della rotellina del mouse per documentare. –

+0

nice - Non ho ricevuto l'evento nell'intera risposta ma non appena hai menzionato "onmousedown", ero già puntato nella giusta direzione - grazie –

3

Ho avuto lo stesso problema.

Il modo più semplice è ovviamente utilizzare jQuery. Si noti che questo metodo potrebbe potenzialmente rallentare la pagina in modo significativo. Inoltre non terrà conto di eventuali nuovi elementi aggiunti dopo che l'evento è stato associato.

$("*").scroll(function(e) { 
    // Handle scroll event 
}); 

In vaniglia JavaScript, è possibile impostare la useCapture booleana per true sul addEventListener chiamata, e sarà il fuoco su tutti gli elementi, compresi quelli aggiunti in modo dinamico.

document.addEventListener('scroll', function(e) { 
    // Handle scroll event 
}, true); 

Nota che questo si attiva prima che l'evento di scorrimento si verifichi effettivamente. A quanto ho capito, passano due fasi. La fase di acquisizione viene eseguita per prima e inizia dalla radice della pagina (ownerDocument?) e attraversa fino all'elemento in cui si è verificato l'evento. Dopo questo arriva la fase di bubbling, che attraversa dall'elemento indietro fino alla radice.

Alcuni test rapidi hanno dimostrato che questo potrebbe essere il modo in cui jQuery lo gestisce (per tracciare pergamene su tutti gli elementi della pagina almeno), ma non sono sicuro al 100%.

Ecco un JSFiddle mostrando JavaScript metodo la vaniglia http://jsfiddle.net/0qpq8pcf/

+2

Stai attento con il primo approccio, perché collega i listener di eventi a ogni singolo elemento DOM può rendere le cose MOLTO lente (per non parlare del fatto che questo non tiene conto degli elementi aggiunti dopo aver creato il gestore di eventi). Il secondo è probabilmente preferibile, ma dovresti anche rimuoverlo quando non è necessario, se possibile (es. Se vuoi solo sapere quando chiudere un popup o qualcosa del genere, collegalo solo mentre il popup è aperto e rimuovilo quando il popup si chiude). –

38

Il modo più semplice per rilevare tutti gli eventi di scorrimento nel browser moderno sarebbe utilizzando 'catturare', piuttosto che 'ribolle' quando si collega l'evento:

window.addEventListener('scroll', function(){ code goes here }, true) 

Sfortunatamente come sono consapevole non esiste un equivalente nel browser precedente come < = IE8

+1

Tanto apprezzamento per questo – CWitty

1

Il seguente funziona bene quando si desidera, ad esempio chiudere una finestra di dialogo dopo qualsiasi cosa nel backgrou nd è scrollato:

var scrollListener = function(e) { 
    // TODO: hide dialog 
    document.removeEventListener('scroll', scrollListener, true); 
}; 

document.addEventListener('scroll', scrollListener, true); 
Problemi correlati