jQuery scroll () виявляє, коли користувач перестає прокручувати


109

Гаразд із цим ..

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

Я можу сказати, коли хтось прокручує те, що я розумію. Тож з цим я намагаюся зрозуміти, як зловити, коли хтось зупинився. З наведеного вище прикладу ви бачите, що я видаляю клас із набору елементів під час прокрутки. Однак я хочу повернути цей клас, коли користувач перестане прокручувати.

Причиною цього є те, що я маю намір провести показовий показ, поки сторінка прокручується, щоб надати сторінці особливий ефект, над яким я намагаюся працювати. Але той клас, який я намагаюся видалити, прокручуючи конфлікт з цим ефектом, як його ефект прозорості для певної природи.



Чудовий, не зовсім дублюючий, але остаточний переклад того, що я шукав, і допоміг мені врешті вирішити мою проблему. Дякую.
chris

Відповіді:


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

Оновлення

Я написав розширення, щоб покращити jQuery за замовчуванням on-event-handler. Він приєднує до обраних елементів функцію обробника подій для однієї або більше подій і викликає функцію обробника, якщо подія не була запущена протягом заданого інтервалу. Це корисно, якщо ви хочете запустити зворотний дзвінок лише після затримки, як-от подія зміни розміру чи подібне.

Важливо перевірити 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 з причин - це була жахлива ідея. Просто замість цього скористайтесь функцією обгортки "дросель" або "дебютування". Зазначу, що ще десь! :)
yckart

49

Використання джуттера / дебютації jQuery

jQuery debounce є приємним для подібних проблем. jsFidlle

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

Другий параметр - прапор "at_begin". Тут я показав, як виконувати код як при "початку прокрутки", так і "закінченні прокрутки".

Використання Лодаша

Як запропонував Баррі Р, jsFiddle , підкреслення або лодаш також мають дебютацію , кожен з дещо різними апісами.

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

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

Чи можливо одночасно використовувати звичайну функцію прокрутки? $ (window) .scroll (функція () {...});
Даніель Вогелнест

Звичайно, jQuery прив’яже стільки обробників до події, скільки вам захочеться.
Сінетхета

Дякуємо за оновлення цього @BarryP Jsfiddle також надає lo-dash, щоб ви могли уникнути зовнішнього посилання jsfiddle.net/qjggnyhf
Sinetheta

FYI, у мене виникли проблеми, коли швидкі сувої не поверталися назад. Здавалося, що вам потрібно додати кілька мілісекунд до дебюту "STOPPED", інакше це спричиняє перегоновий стан, коли колись STOPPED спрацьовує перед НАЧАЛОМ, і ви в кінцевому підсумку з пунктом застрягаєте так, ніби ви все ще прокручуєте. Я зробив свої 150 і 160 відповідно, і, здавалося, зробив трюк.
CodeChimp

Дякую @CodeChimp, що це акуратно, але я хвилювався щодо обробки крайових справ, виправляючи їх 15 з 16 разів;) Можливо, один обробник із усією логікою всередині був би найбезпечнішим. Перевірте leadingі trailingсамі, то переконаєтеся , що не може бути ніякої плутанини.
Сінетхета

9

Роб W запропонував мені перевірити ще одну посаду тут на стеці, яка була по суті схожою на мою оригінальну. Прочитавши це, я знайшов посилання на сайт:

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

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

$(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
Це здається чудовим, але якщо ви прокручуєте двостороннім жестом на трекпаді або колінчастому колесі, миша не запускається. Це, мабуть, найпоширеніший спосіб прокрутки, що робить це проблематичним.
Адам

1
Гарна думка. Але потенційно існує кілька виправлень для цього. Використання події "миші" колекції jquery або відстеження, якщо спочатку його розміщено, та використання підходу в режимі очікування, як запропонували інші. Але я думаю, що використання комбінації інших відповідей на події колеса миші, і ця відповідь для перетягування смуги прокрутки дасть найточніші результати
Тео

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.