jQuery scroll () определяет, когда пользователь прекращает прокрутку


109

Хорошо с этим ..

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

Я могу сказать, когда кто-то прокручивает, исходя из того, что я понимаю. Таким образом, я пытаюсь понять, как поймать, когда кто-то остановился. Из приведенного выше примера вы можете видеть, что я удаляю класс из набора элементов во время прокрутки. Однако я хочу снова включить этот класс, когда пользователь перестанет прокручивать.

Причина этого в том, что я намерен провести демонстрацию наложения во время прокрутки страницы, чтобы придать странице особый эффект, над которым я пытаюсь работать. Но один класс, который я пытаюсь удалить при прокрутке, конфликтует с этим эффектом, поскольку это эффект прозрачности для некоторой природы.



Потрясающе, не совсем дубликат, но определенно выше того, что я искал, и помог мне в конце концов решить мою проблему. Спасибо.
Крис

Ответы:


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

Обновить

Я написал расширение для улучшения onобработчика событий по умолчанию в jQuery. Он прикрепляет функцию обработчика для одного или нескольких событий к выбранным элементам и вызывает функцию обработчика, если событие не было запущено в течение заданного интервала. Это полезно, если вы хотите запустить обратный вызов только после задержки, например, событие изменения размера или подобное.

Важно проверять github-repo на наличие обновлений!

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));

Используйте его, как любой другой обработчик onили bind-event, за исключением того, что вы можете передать дополнительный параметр в качестве последнего:

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

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

(эта демонстрация используется resizeвместо scroll, но кого это волнует ?!)


Это все еще не на 100% точно: иногда пользователь останавливает и возобновляет прокрутку даже через 250 мс
Арман Биматов

Этот код отлично работает, но полностью сломал виджет автозаполнения jquery ui.
kkazakov

@ArmanBimatov, тогда это будет считаться, поскольку пользователь продолжает прокручивать, что звучит хорошо, не так ли?
godblessstrawberry

Этот тайм-аут срабатывает только тогда, когда события прокрутки останавливаются, а НЕ, когда пользователь прекращает прокрутку. Пользователь может убрать палец с мыши, и прокрутка может продолжаться несколько секунд в зависимости от скорости прокрутки. Это решение не подскажет, когда пользователь прекратил прокрутку.
AndroidDev

1
@abzarak, этот абстрактный помощник ни в коем случае не идеален! Я недавно не обновлял github-repo по причинам - это была ужасная идея. Просто используйте вместо этого функцию-оболочку "throttle" или "debounce". Должен отметить, что и в другом месте! :)
yckart

49

Использование jQuery throttle / debounce

jQuery debounce отлично подходит для таких проблем. jsFidlle

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

Второй параметр - это флаг at_begin. Здесь я показал, как выполнять код как в «начале прокрутки», так и «в конце прокрутки».

Использование Lodash

Как предложил Барри П., jsFiddle , подчеркивание или lodash также имеют debounce, каждый с немного другим apis.

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

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

Можно ли одновременно использовать обычную функцию прокрутки? $ (окно) .scroll (функция () {...});
Даниэль Фогельнест

Конечно, jQuery привяжет к событию столько обработчиков, сколько вам нужно.
Sinetheta

Спасибо за обновление этого @BarryP Jsfiddle также предоставляет lo-dash, поэтому вы можете избежать внешней ссылки jsfiddle.net/qjggnyhf
Sinetheta

К вашему сведению, у меня были проблемы, когда быстрая прокрутка не возвращалась. Казалось, что вам нужно добавить несколько миллисекунд к дебаунсу "STOPPED", иначе это вызовет состояние гонки, когда иногда триггер STOPPED срабатывает перед STARTED, и вы в конечном итоге застреваете элемент, как будто вы все еще прокручиваете. Я сделал свои 150 и 160 соответственно, и, похоже, это помогло.
CodeChimp

Спасибо @CodeChimp, это здорово, но я беспокоился об обработке крайних случаев, исправляя их 15 из 16 раз;) Может быть, один обработчик со всей логикой внутри был бы самым безопасным. Проверьте leadingи trailingсами, потом убедитесь, что не может быть путаницы.
Sinetheta

9

Роб В. предложил мне проверить еще один пост здесь, в стеке, который по сути был похож на мой исходный. Читая это, я нашел ссылку на сайт:

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

На самом деле это помогло мне очень хорошо решить мою проблему после небольшой настройки для моих собственных нужд, но в целом помогло избавиться от множества болтовни и сэкономило мне около 4 часов, чтобы разобраться в ней самостоятельно.

Увидев, что этот пост, кажется, имеет некоторые достоинства, я решил, что вернусь и предоставлю код, изначально найденный по упомянутой ссылке, на тот случай, если автор когда-нибудь решит пойти в другом направлении с сайтом и в конечном итоге уберет ссылку.

(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

Я согласился с некоторыми из приведенных выше комментариев, что прослушивание тайм-аута было недостаточно точным, поскольку оно сработает, когда вы перестанете перемещать полосу прокрутки на достаточно долгое время, а не когда вы перестанете прокручивать. Я думаю, что лучшим решением будет прислушиваться к тому, как пользователь отпускает мышь (mouseup), как только они начинают прокрутку:

$(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 
    });
});

и пример его работы можно увидеть в этом JSFiddle


2
Это кажется отличным, но если вы выполняете прокрутку двумя пальцами на трекпаде или колесом прокрутки, то наведение курсора мыши не выполняется. Это, вероятно, самый распространенный способ прокрутки, что делает его проблематичным.
Adam

1
Хорошая точка зрения. Но, возможно, для этого есть пара исправлений. Использование события jquery 'mousewheel' или отслеживание, если сначала mousedown, и использование подхода тайм-аута, как было предложено другими. Но я думаю, что использование комбинации других ответов на события колесика мыши и этот ответ на перетаскивание полосы прокрутки даст наиболее точные результаты
Тео

3

Вы можете установить интервал, который запускается каждые 500 мс или около того, в следующих строках:

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);

Я не тестировал этот код, но принцип должен работать.


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);

очень маленькая версия с возможностью начала и конца


1

Хорошо, это то, что я использовал раньше. В основном вы смотрите рефери до последнего scrollTop(). Как только ваш тайм-аут очищается, вы проверяете текущий scrollTop()и, если они совпадают, вы завершаете прокрутку.

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

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

  currentScrollTop = $(this).scrollTop()
)

1

Стиль ES6 с проверкой начала прокрутки.

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)
  }
}

Использование:

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

Для тех, кто все еще нуждается в этом, вот решение

  $(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

Это должно работать:

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

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

0

Вот как с этим справиться:

    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

Это обнаруживает остановку прокрутки через 1 миллисекунду (или изменяет ее) с помощью глобального таймера:

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.
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.