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.

chris
źródło
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 ?!)

yckart
źródło
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));
Sinetheta
źródło
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) );
        }
    };

})();
chris
źródło
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

Theo
źródło
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ć.

justinbach
źródło
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

Dieter Bender
źródło
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()
)
matrangam
źródło
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
}))
Ilya Iksent
źródło
0

sprawdź zdarzenie scrollstop jquery mobile

$(document).on("scrollstop",function(){
  alert("Stopped scrolling!");
});
Irshad Pathan
źródło
3
to jQuery mobile, a nie jQuery. prawie wpadłem na tę samą pułapkę;)
katzenhut
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 */
      }
  });

smacaz
źródło
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);
});
Mohamad Hamouday
źródło
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>

Mohammad Ghonchesefidi
źródło
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.
}
Ali Sheikhpour
źródło