2012-03-08 9 views
42

Ho una pagina con "scroll infinito". Calcola la differenza tra la fine della pagina e la pagina corrente e carica più contenuto se questa differenza è abbastanza piccola. Il codice è soemthing come questo utilizzando jQuery:Scorri evento sparando troppe volte. Voglio solo che spari un massimo di, diciamo, una volta al secondo

$(window).on('scroll', function() { 
    if (window.pageYOffset > loadMoreButton.offsetTop - 1000) 
     # load more content via ajax 
} 

Ora, il problema è che ogni volta che scorrere, questo evento spara più volte al di scorrimento. Mi piacerebbe sparare al massimo ogni x millisecondi. Come lo farei?

risposta

37

Controlla il metodo "throttle" della libreria Underscore.js.

http://underscorejs.org/#throttle

L'esempio che dà è esattamente quello che stai chiedendo circa - limitando quanto spesso si deve gestire gli eventi di scorrimento.

+2

abbastanza impressionante, ma sto cercando di evitare eventuali dipendenze. –

+14

Guarda il codice sorgente per sottolineare (che è incredibilmente documentato) e basta tirare il gas. – tkone

0

il fuoco di scorrimento più volte è corretto e dovresti riuscire a ottenere la posizione di scorrimento in modo diverso ogni volta. Penso che sia necessario impostare un timer quando si entra per la prima volta nell'evento di scorrimento come menzionato x millisecondi, e anche registrare il timestamp, e poi la volta successiva scorrere l'evento fire, controllare l'ultima volta del trigger e ignorarlo se è entro x millisecondi e fai il vero lavoro nella tua azione Timer.

6
var isWorking = 0; 

$(window).on('scroll', function() 
{ 
    if(isWorking==0) 
    { 
     isWorking=1; 
     if (window.pageYOffset > loadMoreButton.offsetTop - 1000) 
     # load more content via ajax 
     setTimeout(function(){isWorking=0},1000); 
    } 
} 
+0

Spero che funzioni, non lo testò. Fondamentalmente lancia ogni scroll ma se un'altra copia è in esecuzione non fa nulla, altrimenti aspetta xxx millisecondi e fa il lavoro –

+0

Eeeeck. Non è possibile utilizzare una funzione di sospensione come questa in javascript. Si bloccherà il browser durante il sonno. Javascript è single threaded e blocca il browser. Non puoi scrivere codice javascript come questo. – jfriend00

+0

sì, hai ragione, dimenticati di questo –

30

Un modo per risolvere questo problema è definire un intervallo di tempo e elaborare solo un evento di scorrimento una volta all'interno di tale intervallo di tempo. Se durante questo intervallo di tempo arriva più di un evento di scorrimento, lo ignori e lo elabora solo quando l'intervallo di tempo è trascorso.

var scrollTimer, lastScrollFireTime = 0; 

$(window).on('scroll', function() { 

    var minScrollTime = 100; 
    var now = new Date().getTime(); 

    function processScroll() { 
     console.log(new Date().getTime().toString()); 
    } 

    if (!scrollTimer) { 
     if (now - lastScrollFireTime > (3 * minScrollTime)) { 
      processScroll(); // fire immediately on first scroll 
      lastScrollFireTime = now; 
     } 
     scrollTimer = setTimeout(function() { 
      scrollTimer = null; 
      lastScrollFireTime = new Date().getTime(); 
      processScroll(); 
     }, minScrollTime); 
    } 
}); 

Questa sparerà il primo evento di scorrimento immediatamente e poi si ottiene un evento di scorrimento circa una volta ogni 100 ms, mentre la barra di scorrimento viene spostato e quindi un evento finale dopo la barra di scorrimento smette di muoversi. È possibile regolare la frequenza dell'evento modificando l'argomento su setTimeout (cosa è attualmente impostato su 100).

C'è una demo qui: http://jsfiddle.net/jfriend00/EBEqZ/ che è necessario aprire una finestra della console di debug, avviare lo spostamento della barra di scorrimento nella finestra del contenuto e quindi guardare l'ora di ogni evento di scorrimento nella finestra della console di debug. Sulla mia versione di Chrome, sono impostati per una spaziatura minima di 100 ms e sembrano verificarsi ogni 100-200 ms.

+0

Ciao Jimmy, quando premo il tasto "fine" della tastiera sulla mia pagina infinita, sembra che processScroll si attivi due volte. Come posso risolverlo? – horse

+0

@ user2356198 - Ecco una versione che risolve il problema: http://jsfiddle.net/v8e7aLy6/ – jfriend00

+0

Va bene per il tasto "fine", ma quando scorro velocemente, si attiva due volte. Non c'è nessun problema in slow scroll. – horse

4
var now = new Date().getTime(); 
$(window).scroll(function() { 
    if (window.pageYOffset > loadMoreButton.offsetTop - 1000) 
    { 
     if (new Date().getTime() - now > 1000) 
     { 
      console.log("Task executed once per second"); 
      now = new Date().getTime(); 
     } 
    } 
}); 

O

È possibile utilizzare Throttling fonction chiamate: throttling-function-calls

function throttle(fn, threshhold, scope) { 
    threshhold || (threshhold = 250); 
    var last, 
     deferTimer; 
    return function() { 
    var context = scope || this; 

    var now = +new Date, 
     args = arguments; 
    if (last && now < last + threshhold) { 
     // hold on to it 
     clearTimeout(deferTimer); 
     deferTimer = setTimeout(function() { 
     last = now; 
     fn.apply(context, args); 
     }, threshhold); 
    } else { 
     last = now; 
     fn.apply(context, args); 
    } 
    }; 
} 

È possibile chiamare in questo modo:

$('body').on('mousemove', throttle(function (event) { 
    console.log('tick'); 
}, 1000)); 
+2

Si prega di aggiungere alcuni commenti e descrizioni a questo codice. –

3

Ecco una soluzione che doesn 'richiedono l'uso di un extr una libreria o un plugin JS, che mira alla semplicità. Potrebbe non essere efficiente come altre implementazioni, ma è sicuramente un passo avanti nel licenziare il tuo evento principale ogni volta che scorri.

Questo è stato preso da questo blog post da Danny Van Kooten. Che ho utilizzato per ritardare i miei eventi onscroll() per il mio pulsante back-to-top sul mio blog.

var timer; 
$(window).scroll(function() { 
    if(timer) { 
     window.clearTimeout(timer); 
    } 
    timer = window.setTimeout(function() { 
     // actual code here. Your call back function. 
    console.log("Firing!"); 
    }, 100); 
}); 

È inoltre possibile migliorare ulteriormente le prestazioni spostando fuori variabili fuori dalla funzione di callback per evitare calcoli inutili, ad esempio, il valore di $(window).height() o altezza di qualche elemento div statica che non cambierà una volta che la pagina viene caricata .

Ecco un esempio che viene adattato dal mio caso d'uso.

var scrollHeight = $("#main-element").height(); //never changes, no need to recalculate. 
$(window).on('scroll', function() { 
    if (timer) 
     window.clearTimeout(timer); 
    timer = window.setTimeout(function() { 
     var scrollPosition = $(window).height() + $(window).scrollTop();  
     if ($(window).scrollTop() < 500) 
      $(".toggle").fadeIn(800); 
     else 
      $(".toggle").fadeOut(800); 
    }, 150); //only fire every 150 ms. 
}); 

Questo limita la funzione che deve essere eseguito solo ogni 150ms, oppure resettare il timer di nuovo a 0 se 150ms non è passato. Modifica il valore per adattarlo alle tue esigenze.

9

C'è una bella spiegazione da John Resig, il creatore di jQuery per risolvere questa situazione.

var outerPane = $details.find(".details-pane-outer"), 
    didScroll = false; 

$(window).scroll(function() { 
    didScroll = true; 
}); 

setInterval(function() { 
    if (didScroll) { 
     didScroll = false; 
     // Check your page position and then 
     // Load in more results 
    } 
}, 250); 

La fonte: biblioteca http://ejohn.org/blog/learning-from-twitter/

Problemi correlati