jQuery scroll () wykrywa, kiedy użytkownik przestaje przewijać


109

Ok z tym…

$(window).scroll(function()
{
    $('.slides_layover').removeClass('showing_layover');
    $('#slides_effect').show();
});

Z tego, co rozumiem, mogę stwierdzić, kiedy ktoś przewija. Dlatego próbuję wymyślić, jak złapać, gdy ktoś się zatrzymał. Z powyższego przykładu widać, że usuwam klasę z zestawu elementów podczas przewijania. Jednak chcę ponownie włączyć tę klasę, gdy użytkownik przestanie przewijać.

Powodem tego jest to, że zamierzam mieć pokaz na postój podczas przewijania strony, aby nadać stronie specjalny efekt, nad którym próbuję pracować. Ale jedna klasa, którą próbuję usunąć podczas przewijania, jest sprzeczna z tym efektem, ponieważ jest to efekt przezroczystości w pewnym sensie.



Niesamowite, niezupełnie zduplikowane, ale ostatecznie w alei tego, czego szukałem i pomogło mi w końcu rozwiązać mój problem. Dziękuję Ci.
chris

Odpowiedzi:


253
$(window).scroll(function() {
    clearTimeout($.data(this, 'scrollTimer'));
    $.data(this, 'scrollTimer', setTimeout(function() {
        // do something
        console.log("Haven't scrolled in 250ms!");
    }, 250));
});

Aktualizacja

Napisałem rozszerzenie, aby ulepszyć domyślną onobsługę zdarzeń w jQuery . Dołącza funkcję obsługi zdarzenia dla jednego lub większej liczby zdarzeń do wybranych elementów i wywołuje funkcję obsługi, jeśli zdarzenie nie zostało wyzwolone dla danego interwału. Jest to przydatne, jeśli chcesz wywołać wywołanie zwrotne dopiero po opóźnieniu, takim jak zdarzenie zmiany rozmiaru itp.

Ważne jest, aby sprawdzić repozytorium github pod kątem aktualizacji!

https://github.com/yckart/jquery.unevent.js

;(function ($) {
    var on = $.fn.on, timer;
    $.fn.on = function () {
        var args = Array.apply(null, arguments);
        var last = args[args.length - 1];

        if (isNaN(last) || (last === 1 && args.pop())) return on.apply(this, args);

        var delay = args.pop();
        var fn = args.pop();

        args.push(function () {
            var self = this, params = arguments;
            clearTimeout(timer);
            timer = setTimeout(function () {
                fn.apply(self, params);
            }, delay);
        });

        return on.apply(this, args);
    };
}(this.jQuery || this.Zepto));

Użyj go jak każdego innego programu obsługi onlub bind-event, z wyjątkiem tego, że możesz przekazać dodatkowy parametr jako ostatni:

$(window).on('scroll', function(e) {
    console.log(e.type + '-event was 250ms not triggered');
}, 250);

http://yckart.github.com/jquery.unevent.js/

(to demo używa resizezamiast scroll, ale kogo to obchodzi ?!)


To wciąż nie jest w 100% dokładne: czasami użytkownik zatrzymuje i wznawia przewijania nawet po 250 ms
Arman Bimatov

Ten kod działa świetnie, ale całkowicie zepsuł widżet autouzupełniania jquery ui.
kkazakov

@ArmanBimatov to zostanie uwzględnione, ponieważ użytkownik przewija dalej, co brzmi dobrze, prawda?
godblessstrawberry

Ten limit czasu jest uruchamiany tylko wtedy, gdy zdarzenia przewijania zatrzymają się, a NIE, gdy użytkownik przestaje przewijać. Użytkownik może zdjąć palec z myszy i przewijanie może trwać kilka sekund w zależności od szybkości przewijania. To rozwiązanie nie wskaże, kiedy użytkownik przestał przewijać.
AndroidDev

1
@abzarak ten abstrakcyjny pomocnik nie jest doskonały, w żadnym wypadku! Nie aktualizowałem ostatnio repozytorium github z powodów - to był okropny pomysł. Zamiast tego użyj po prostu funkcji opakowującej „throttle” lub „debounce”. Powinienem zauważyć, że gdzie indziej! :)
yckart

49

Korzystanie z jQuery throttle / debounce

jQuery debounce jest dobrym rozwiązaniem w przypadku takich problemów. jsFidlle

$(window).scroll($.debounce( 250, true, function(){
    $('#scrollMsg').html('SCROLLING!');
}));
$(window).scroll($.debounce( 250, function(){
    $('#scrollMsg').html('DONE!');
}));

Drugim parametrem jest flaga „at_begin”. Tutaj pokazałem, jak wykonać kod zarówno na „początku przewijania”, jak i „zakończeniu przewijania”.

Korzystanie z Lodash

Jak zasugerował Barry P, jsFiddle , podkreślenie lub lodash również mają odbicie , każdy z nieco innym apis.

$(window).scroll(_.debounce(function(){
    $('#scrollMsg').html('SCROLLING!');
}, 150, { 'leading': true, 'trailing': false }));

$(window).scroll(_.debounce(function(){
    $('#scrollMsg').html('STOPPED!');
}, 150));

Czy można jednocześnie korzystać z normalnej funkcji przewijania? $ (okno) .scroll (funkcja () {...});
Daniel Vogelnest

Oczywiście jQuery będzie wiązać ze zdarzeniem tyle programów obsługi, ile chcesz.
Sinetheta

Dzięki za aktualizację tego @BarryP Jsfiddle zapewnia również lo-dash, dzięki czemu można uniknąć zewnętrznego linku jsfiddle.net/qjggnyhf
Sinetheta

FYI, miałem problemy, w których szybkie zwoje nie wracały. Wydawało się, że trzeba było dodać kilka milisekund do odbicia „ZATRZYMANY”, w przeciwnym razie powoduje to stan wyścigu, w którym czasami ZATRZYMANY uruchamia się przed STARTEM i kończy się z zablokowaniem elementu, tak jakby nadal był przewijany. Zrobiłem odpowiednio 150 i 160 i wydawało się, że to załatwiło sprawę.
CodeChimp

Dzięki @CodeChimp, to fajne, ale martwiłem się o obsługę skrajnych przypadków, naprawiając je 15 z 16 razy;) Może najbezpieczniejszy byłby pojedynczy program obsługi z całą logiką w środku. Sprawdź leadingi trailingsiebie, a następnie upewnij się, że nie ma zamieszania.
Sinetheta

9

Rob W zasugerował, żebym sprawdził inny post na stosie, który był zasadniczo podobny do mojego oryginalnego. W którym czytaniu znalazłem link do strony:

http://james.padolsey.com/javascript/special-scroll-events-for-jquery/

To faktycznie pomogło mi bardzo ładnie rozwiązać mój problem po drobnych poprawkach dla moich własnych potrzeb, ale w sumie pomogło mi to zrzucić z drogi wiele bzdur i zaoszczędziło mi około 4 godzin samodzielnego rozwiązania tego problemu.

Widząc, że ten post wydaje się mieć jakąś wartość, pomyślałem, że wrócę i przekażę kod znaleziony pierwotnie pod wymienionym linkiem, na wypadek gdyby autor zdecydował się kiedykolwiek pójść w innym kierunku ze stroną i ostatecznie usunął link.

(function(){

    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);

    special.scrollstart = {
        setup: function() {

            var timer,
                handler =  function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);
                    }

                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid1, handler);

        },
        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
        }
    };

    special.scrollstop = {
        latency: 300,
        setup: function() {

            var timer,
                    handler = function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    }

                    timer = setTimeout( function(){

                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);

                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid2, handler);

        },
        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
        }
    };

})();

5

Zgodziłem się z niektórymi komentarzami powyżej, że nasłuchiwanie limitu czasu nie było wystarczająco dokładne, ponieważ uruchomi się, gdy przestaniesz przesuwać pasek przewijania na wystarczająco długo, a nie gdy przestaniesz przewijać. Myślę, że lepszym rozwiązaniem jest nasłuchiwanie, jak użytkownik puszcza mysz (ruch myszką), gdy tylko zacznie przewijać:

$(window).scroll(function(){
    $('#scrollMsg').html('SCROLLING!');
    var stopListener = $(window).mouseup(function(){ // listen to mouse up
        $('#scrollMsg').html('STOPPED SCROLLING!');
        stopListner(); // Stop listening to mouse up after heard for the first time 
    });
});

a przykład jego działania można zobaczyć w tym JSFiddle


2
Wydaje się to świetne, ale jeśli przewijasz gestem 2 palcami na gładziku lub kółku przewijania, mysz nie zostanie uruchomiona. Jest to prawdopodobnie najpopularniejszy sposób przewijania, co sprawia, że ​​jest problematyczny.
Adam

1
Słuszna uwaga. Ale potencjalnie jest na to kilka poprawek. Korzystanie ze zdarzenia „mousewheel” jquery lub śledzenie pierwszego ruchu myszy i stosowanie podejścia do limitu czasu zgodnie z sugestiami innych. Ale myślę, że użycie kombinacji innych odpowiedzi dla zdarzeń kółka myszy i tej odpowiedzi dla przeciągania paska przewijania da najdokładniejsze wyniki
Theo

3

Możesz ustawić interwał, który będzie uruchamiany co około 500 ms, zgodnie z poniższymi wskazówkami:

var curOffset, oldOffset;
oldOffset = $(window).scrollTop();
var $el = $('.slides_layover'); // cache jquery ref
setInterval(function() {
  curOffset = $(window).scrollTop();
  if(curOffset != oldOffset) {
    // they're scrolling, remove your class here if it exists
    if($el.hasClass('showing_layover')) $el.removeClass('showing_layover');
  } else {
    // they've stopped, add the class if it doesn't exist
    if(!$el.hasClass('showing_layover')) $el.addClass('showing_layover');
  }
  oldOffset = curOffset;
}, 500);

Nie testowałem tego kodu, ale zasada powinna działać.


2
function scrolled() {
    //do by scroll start
    $(this).off('scroll')[0].setTimeout(function(){
        //do by scroll end
        $(this).on('scroll',scrolled);
    }, 500)
}
$(window).on('scroll',scrolled);

bardzo mała wersja z możliwością rozpoczęcia i zakończenia


1

Ok, to jest coś, czego używałem wcześniej. Zasadniczo wyglądasz na trzymającego się odniesienia do ostatniego scrollTop(). Po wyczyszczeniu limitu czasu sprawdzasz bieżący scrollTop()i jeśli są takie same, skończyłeś przewijanie.

$(window).scroll((e) ->
  clearTimeout(scrollTimer)
  $('header').addClass('hidden')

  scrollTimer = setTimeout((() ->
    if $(this).scrollTop() is currentScrollTop
      $('header').removeClass('hidden') 
  ), animationDuration)

  currentScrollTop = $(this).scrollTop()
)

1

Styl ES6 ze sprawdzaniem rozpoczęcia przewijania również.

function onScrollHandler(params: {
  onStart: () => void,
  onStop: () => void,
  timeout: number
}) {
  const {onStart, onStop, timeout = 200} = params
  let timer = null

  return (event) => {
    if (timer) {
      clearTimeout(timer)
    } else {
      onStart && onStart(event)
    }
    timer = setTimeout(() => {
      timer = null
      onStop && onStop(event)
    }, timeout)
  }
}

Stosowanie:

yourScrollableElement.addEventListener('scroll', onScrollHandler({
  onStart: (event) => {
    console.log('Scrolling has started')
  },
  onStop: (event) => {
    console.log('Scrolling has stopped')
  },
  timeout: 123 // Remove to use default value
}))


0

Dla tych, którzy wciąż tego potrzebują, oto rozwiązanie

  $(function(){
      var t;
      document.addEventListener('scroll',function(e){
          clearTimeout(t);
          checkScroll();
      });
      
      function checkScroll(){
          t = setTimeout(function(){
             alert('Done Scrolling');
          },500); /* You can increase or reduse timer */
      }
  });


0

To powinno działać:

var Timer;
$('.Scroll_Table_Div').on("scroll",function() 
{
    // do somethings

    clearTimeout(Timer);
    Timer = setTimeout(function()
    {
        console.log('scrolling is stop');
    },50);
});

0

Oto, jak możesz sobie z tym poradzić:

    var scrollStop = function (callback) {
        if (!callback || typeof callback !== 'function') return;
        var isScrolling;
        window.addEventListener('scroll', function (event) {
            window.clearTimeout(isScrolling);
            isScrolling = setTimeout(function() {
                callback();
            }, 66);
        }, false);
    };
    scrollStop(function () {
        console.log('Scrolling has stopped.');
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
</body>
</html>


0

Wykrywa zatrzymanie przewijania po 1 milisekundzie (lub zmień je) za pomocą globalnego zegara:

var scrollTimer;

$(window).on("scroll",function(){
    clearTimeout(scrollTimer);
    //Do  what you want whilst scrolling
    scrollTimer=setTimeout(function(){afterScroll()},1);
})

function afterScroll(){
    //I catched scroll stop.
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.