web-dev-qa-db-ja.com

jQueryでスクロールイベントが手動でトリガーされたかどうかを検出する

この質問はずっと前にここですでに尋ねられました:

ユーザーによるjqueryイベントトリガーの検出またはコードによる呼び出し

しかし、それは決定的に答えられたことはありません(または、おそらく私は単に適切に検索することができません)。

scrollイベントがユーザーによってトリガーされたか、jQuery animate関数によってトリガーされたかを検出することはできますか?

私はscrollイベントが次のようなことをしている間に自分自身をトリガーするのを防ぎたいと思っています:

$(document).scroll(function(){
    $("html").stop(true);
    var number = 400; //some other stuff is happening here
    clearTimeout(tout);
    tout = setTimeout(function(){
        if(top == $(document).scrollTop()){
            $("html").animate({
                scrollTop: (number),
                easing: "easeInQuad",
                duration: 110
            });
        }
    },120);
});

このコードは適しているようです:

$('#scroller').scroll(function(e) {
    if (e.originalEvent) {
        console.log('scroll happen manual scroll');
    } else {
        console.log('scroll happen by call');
    }
});

ただし、originalEventオブジェクトは、アニメーショントリガーを適切に検出できません。

これを行う他の方法はありますか?

12
BluBb_mADe

多分 :animatedセレクターが役立ちます:

$('#scroller').scroll(function(e) {
    if ($(this).is(':animated')) {
        console.log('scroll happen by animate');
    } else if (e.originalEvent) {
        // scroll happen manual scroll
        console.log('scroll happen manual scroll');
    } else {
        // scroll happen by call
        console.log('scroll happen by call');
    }
});

デモ

19
Tony

これがタッチスクリーンデバイスでどのように機能するかはわかりませんが、少なくともデスクトップでは機能します

$(window).on('mousewheel', function(){
    //code that will only fire on manual scroll input
});

$(window).scroll(function(){
    //code that will fire on both mouse scroll and code based scroll
});

アニメーションの巻物だけをターゲットにする方法はないと思います(受け入れられた答えは私にとってはうまくいきませんでした)。

更新:警告!

残念ながら、'mousewheel'は、手動でスクロールバーをつかんでドラッグするユーザーや、スクロールバーの矢印ボタンを使用するユーザーをピックアップしないようです:(

タッチスクリーンデバイスでは、スワイプがマウススクロールとしてカウントされるように見えるため、これは問題なく動作します。ただし、これはデスクトップユーザーには最適なソリューションではありません。

6
Daniel Tonon

@Tonyの受け入れられた回答と@DanielTononのコメントを使用して、次の解決策を思いつきました。

_  var animatedScroll = false;
  var lastAnimatedScroll = false;
  $(window).scroll(function(event){
    lastAnimatedScroll = animatedScroll;
    animatedScroll = $('html, body').is(':animated');
  });
_

これにより、jqueryが.is(':animated')を削除してから1ピクセル以上スクロールするという前述の問題が解決され、.is(':animated')がfalseで終了するようになります。 .is(':animated')の最後から2番目のバージョンを保存することで、スクロールがアニメーションであるかどうかを(さらに)確認できます。

スクロールがアニメーション化されているかどうかを知りたいときは、lastAnimatedScroll変数を確認してください。

これは私によって徹底的にテストされていませんが、多くのページの更新で正しいため、十分に機能すると想定します。

2
cwal

この問題でさまざまなソリューションを実装しようとした後、私は自分にとってうまく機能している別のアプローチを思いつきました。

アニメーションが実行されているかどうかに手動のブール値を使用します。

var isRunningAnimation = false;

アニメーション化する直前にtrueに設定し、jQuery falseコールバック関数でanimateに設定します。

  isRunningAnimation = true;

  $('html').animate({
    scrollLeft: 100,
    scrollTop:  100
  }, 400, 'swing', function() {
    isRunningAnimation = false;
  });

次に、スクロールリスナーでそのブール値を確認します。

$('scroll', function() {
  if (!isRunningAnimation) {
    // If we made it to here, the animation isn't running
  }
});

もちろん、技術的には、ユーザーがアニメーション中に手動でスクロールすることを決定した場合、スクロール時のロジックもトリガーされませんが、これは心配する必要がないEdgeケースのように思えます。

1
SubJunk

まず、JavaScript関数を作成することをお勧めします

// Attaching scroll event when document/window is loaded
    function OnFirstLoad() {
        if (document.attachEvent) {
            document.attachEvent('onscroll', scrollEvent);
        } else if (document.addEventListener) {
            document.addEventListener('scroll', scrollEvent, false);
        }

    }

次に、どちらかを使用します

        window.onload = OnFirstLoad;

または

    $(document).ready(function () {
         OnFirstLoad();
    });

このスクロールイベントは関数です

function scrollEvent(e) {
        var body = document.body,
             html = document.documentElement;

        var docHeight = Math.max(body.scrollHeight, body.offsetHeight,
                               html.clientHeight, html.scrollHeight, html.offsetHeight);
        var currentScroll = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
        // implement your logic according to requirement

    }
1
Hitesh Gaur