jQuery scroll()は、ユーザーがスクロールを停止したことを検出します


109

これでOK

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

私が理解しているものから誰かがスクロールしていることを知ることができます。ですから、誰かが止まったときにどうやって捕まえるかを考えています。上記の例から、スクロールが行われている間に、要素のセットからクラスを削除していることがわかります。ただし、ユーザーがスクロールを停止したときにそのクラスを元に戻したいと思います。

この理由は、ページをスクロールしている間、私が取り組んでいる特別な効果をページに与えるために、レイオーバーショーを行うことです。しかし、スクロール中に削除しようとしている1つのクラスは、ある種の性質に対する透過効果として、その効果と競合します。



素晴らしく、正確に重複しているわけではありませんが、私が探していたものの路地を明確に示し、最終的に私が問題を解決するのを助けました。ありがとうございました。
クリス

回答:


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

更新

jQueryのデフォルトの-event-handlerを拡張する拡張機能on作成しました。1つ以上のイベントのイベントハンドラー関数を選択した要素にアタッチし、イベントが特定の間隔でトリガーされなかった場合はハンドラー関数を呼び出します。これは、サイズ変更イベントなど、遅延の後でのみコールバックを起動する場合に便利です。

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ミリ秒後にも停止してスクロールを再開することがあります
Arman Bimatov 2014年

このコードはうまく機能しますが、jquery uiのオートコンプリートウィジェットを完全に壊しました。
kkazakov 2015

@ArmanBimatovでは、ユーザーがスクロールし続けると見なされます。
godblessstrawberry 2016年

このタイムアウトは、スクロールイベントが停止したときにのみ発生し、ユーザーがスクロールを停止したときに発生しません。ユーザーはマウスから指を離すことができ、スクロールの速度に応じてスクロールを数秒間継続できます。この解決策は、ユーザーがスクロールを停止したことを示しません。
AndroidDev 2017年

1
@abzarakこの抽象ヘルパーは決して完璧ではありません!私は理由から最近github-repoを更新していません—これはひどい考えでした。代わりに、「スロットル」または「デバウンス」ラッパー関数を使用してください。他の場所にも注意してください!:)
yckart 2017年

49

jQueryスロットルの使用/デバウンス

jQueryデバウンスは、このような問題に適したものです。jsFidlle

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

2番目のパラメーターは「at_begin」フラグです。ここでは、「スクロール開始」と「スクロール終了」の両方でコードを実行する方法を示しました。

Lodashの使用

Barry Pによって示唆されているように、jsFiddleアンダースコア、またはlodashにもデバウンスがあり、それぞれがapiがわずかに異なります。

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

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

通常のスクロール機能を併用することはできますか?$(window).scroll(function(){...});
Daniel Vogelnest 2013年

もちろん、jQueryは必要な数のハンドラーをイベントにバインドします。
Sinetheta 2013年

この@BarryPを更新していただきありがとうございます。Jsfiddleはlo-dashも提供するため、外部リンクjsfiddle.net/qjggnyhfを
Sinetheta

ちなみに、早送りが元に戻らないという問題がありました。「STOPPED」のデバウンスに数ミリ秒を追加する必要があるようですが、そうでない場合、STARTPの前にSTOPPEDがトリガーし、スクロールしているようにアイテムがスタックしたままになるという競合状態が発生します。私はそれぞれ150と160を作りました、そしてそれはトリックをするようでした。
CodeChimp 2016年

素晴らしい@CodeChimpに感謝しますが、エッジケースを16回のうち15回修正して処理することを心配していました;)おそらく、すべてのロジックが含まれる単一のハンドラーが最も安全でしょう。leadingtrailing自分自身を確認し、混乱がないことを確認してください。
Sinetheta 2016年

9

Rob 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
これはすばらしいように見えますが、トラックパッドの2本指ジェスチャーまたはスクロールホイールでスクロールしている場合、マウスアップは発生しません。これもおそらく最も一般的なスクロール方法であり、問​​題を引き起こします。
Adam

1
いい視点ね。しかし、潜在的にそのための修正がいくつかあります。jqueryの「マウスホイール」イベントを使用するか、最初にマウスダウンした場合に追跡し、他の人が提案するタイムアウトアプローチを使用します。しかし、マウスホイールイベントに他の回答を組み合わせて使用​​し、スクロールバーのドラッグにこの回答を使用すると、最も正確な結果が得られると思います
Theo

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.
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.