2011-08-12 17 views
54

スクロールイベントがブラウザまたはユーザーによって行われたかどうかを確認することはできますか?具体的には、戻るボタンを使用するとき、ブラウザは最後の既知のスクロール位置にジャンプすることができる。私がスクロールイベントにバインドする場合、これがユーザーまたはブラウザによって引き起こされたかどうかをどのように伝えることができますか?スクロールイベントがユーザーによって作成されたかどうかを検出します。

$(document).scroll(function(){ 
    //who did this?! 
}); 

ブラウザでスクロールする3つの状況があります。

  1. ユーザーは何らかのアクションを実行します。例えば、マウスホイール、矢印キー、ページアップ/ダウンキー、ホーム/エンドキーを使用します。
  2. ブラウザが自動的にスクロールします。たとえば、ブラウザで戻るボタンを使用すると、最後の既知のスクロール位置に自動的にジャンプします。
  3. Javascriptのスクロールです。たとえば、element.scrollTo(x,y)です。
+1

あなたがブラウザまたはユーザーのスクロールイベントのバックボトルトンを使用してジャンプを検討する場合、私はあなたの質問から分からない。一般的には、「ブラウザのスクロール」とは何でしょうか?スクリプトによって開始されたスクロールを意味する場合は、スクリプトがスクロールしてイベントハンドラを非アクティブ化するか、またはフラグを設定してイベントハンドラが無視することを知ることができます。 – RoToRa

+0

私は、戻るボタンを使ってスクロールすることを "ブラウザスクロール"と考えました。それ以外のもの - マウスホイール、上下矢印、センターボタンクリックなどはユーザーのスクロールです。私の本当の疑問は、イベントがどこから来たのかを区別する手段があるのだろうか?私はイベントオブジェクトのプロパティを見ましたが、何も見つかりませんでした。私が想像できる3つのシナリオは、ブラウザが開始したスクロール、javascript開始のスクロール、およびユーザーが開始したスクロールです。事がより明確になることを願っています。 – mrtsherman

+0

@mrtsherman同じ出力を達成しながらこれらのいくつかを見つけました: http://stackoverflow.com/questions/2834667/how-can-i-differentiate-a-manual-scroll-via-mousewheel-scrollbar-from- a-javasc – AlphaMale

答えて

17

残念ながら、それを伝える直接的な方法はありません。

あなたのアプリをに再設計して、このタイプのフローに依存しないようにすればいいと思います。

回避策私は、ユーザーが開始したスクロールを追跡し、スクロールがブラウザまたはユーザーによってトリガーされたかどうかを確認することが考えられます。

これは私がまとめた例ですが、これはかなりうまくいきます(jQueryの履歴に問題があるブラウザを除く)。

これを完全にテストするには、ローカルで実行する必要があります(jsFiddle/jsbinは内容を確認するのに適していません)。userScrollは、ページ下部にジャンプするリンク上true

  • クリックなった - - userScrollfalse
  • スクロール用いて、マウス/キーボードである

    • ページのロード:ここ

      は、私が検証さテストケースです - userScrollfalse
    • になります。戻る/進む - userScrollfalseになります。

    <!DOCTYPE html> 
    <html lang="en"> 
    <head> 
        <meta charset="utf-8" /> 
        <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script> 
        <script type="text/javascript" src="https://raw.github.com/tkyk/jquery-history-plugin/master/jquery.history.js"></script> 
    </head> 
    <body> 
        <span> hello there </span><br/> 
        <a href="#bottom"> click here to go down </a> 
        <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
        <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
        <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
        <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
        <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
        <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
        <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
        <a name="bottom"> just sitting </a> 
    </body> 
    <script type="text/javascript"> 
    
    var userScroll = false;  
    
    function mouseEvent(e) { 
        userScroll = true; 
    } 
    
    
    $(function() { 
    
        // reset flag on back/forward 
        $.history.init(function(hash){ 
         userScroll = false; 
        }); 
    
        $(document).keydown(function(e) { 
         if(e.which == 33  // page up 
          || e.which == 34  // page dn 
          || e.which == 32  // spacebar 
          || e.which == 38  // up 
          || e.which == 40  // down 
          || (e.ctrlKey && e.which == 36)  // ctrl + home 
          || (e.ctrlKey && e.which == 35)  // ctrl + end 
         ) { 
          userScroll = true; 
         } 
        }); 
    
        // detect user scroll through mouse 
        // Mozilla/Webkit 
        if(window.addEventListener) { 
         document.addEventListener('DOMMouseScroll', mouseEvent, false); 
        } 
    
        //for IE/OPERA etc 
        document.onmousewheel = mouseEvent; 
    
    
        // to reset flag when named anchors are clicked 
        $('a[href*=#]').click(function() { 
         userScroll = false; 
        }); 
    
         // detect browser/user scroll 
        $(document).scroll(function(){ 
         console.log('Scroll initiated by ' + (userScroll == true ? "user" : "browser")); 
        }); 
    }); 
    </script> 
    </html> 
    

    注:

    • をユーザーがマウスでスクロールバーをドラッグしたときにこれはスクロールを追跡しません。これは、私があなたのための練習として残したいくつかのコードで追加することができます。
    • event.keyCodesはOSによって異なる場合がありますので、適切に変更する必要があります。

  • +0

    ありがとう、Mrchief。私はこれが最高の答えだと思っていますが、それは私が望んでいたものではありません(何ですか?event.thrower'プロパティはありませんか?)。 – mrtsherman

    2

    代わりにMousewheelとDOMMouseScrollイベントを使用してみてください。 http://www.quirksmode.org/dom/events/scroll.html

    +0

    この提案をありがとうございます。しかし、私はこれが私の望むものとは思わない。私は実際にブラウザとユーザーのスクロールを区別する必要があります。マウスホイールをターゲットにするだけではありません。 – mrtsherman

    +0

    mousewheelイベントはonscrollイベントの前に発生すると思います。したがって、mousewheelでvar userscroll = trueを設定し、それをonscrollで検出して(falseにリセットする)ことができます。 – Gerben

    +2

    ユーザーが開始した多数のスクロールイベントがありますが、これはカバーされません。矢印キー、ウィンドウのサイズ変更などこのイベントの送信者は "X"でなければならないと言うよりもはるかに安全です。それは私がブラウザではなくユーザによって開始されたスクロールを識別したいので、私には関係なく動作しません。だから、このユースケースを作るには、すべてのマウスホイールのスクロールを追跡し、その後のスクロールイベントがそれに基づいているのかどうかを推測しなければなりません。私はそれがちょうどうまくいかないのではないかと心配しています。 – mrtsherman

    6

    私が知っている限り、スクロールイベントが「ユーザー」または他の手段によって発行されたときはいつでも通知することはできません。

    マウスホイールイベントをキャッチしようとしている可能性があります。たとえば、現在フォーカスされている要素を確認しながらスクロール(矢印、スペースなど)をトリガーできるキーでkeydownイベントをキャッチしようとしている可能性があります。入力フィールドに入力中に矢印キーを使用してスクロールします。 一般に、それは複雑で面倒なスクリプトになります。

    私は「ロジックを元に戻す」、そして代わりにユーザーに発行スクロールイベントを検出するだけで、プログラムで行われた巻物にフックし、任意のスクロールイベントを扱う推測できますが、あなたを扱っている状況に応じて、あなたのコードで行われていないユーザによって行われる。 私が言ったように、それは状況に左右され、あなたは何をしようとしているのですか。

    +0

    ありがとうWTK。これはしばらくの間の最善の答えでしたが、残念ながらMrchiefはいくつかのコード例であなたの答えを解説しましたので、私は彼に恩恵を与えました。私はそれを分割することができたら私は持っていただろう! – mrtsherman

    +2

    これは問題ありません。賞金についてではなく、知識を広めて得ようとしています:) – WTK

    1

    準備完了時にスクロール位置を確認できます。スクロールイベントを発生させるときは、ページがロードされたときとスクロール位置が異なることを確認します。最後に、一度ページをスクロールすると、必ず保存された値をクリアしてください。

    $(function() { 
        var loadScrollTop = ($(document).scrollTop() > 0 ? $(document).scrollTop() : null); 
        $(document).scroll(function (e) { 
         if ($(document).scrollTop() !== loadScrollTop) { 
          // scroll code here! 
         } 
         loadScrollTop = null; 
        }); 
    }); 
    
    +0

    このアイデアをありがとう。これは私のためにカバーしていないいくつかのシナリオがあります。それは良い考えですが、私はそれが必要な場合は私のバックポケットに保管します。 – mrtsherman

    0

    これは非常に有用です。そのように傾けられた人のためのcoffeescript版があります。

    $ -> 
        S.userScroll = false 
    
        # reset flag on back/forward 
        if $.history? 
        $.history.init (hash) -> 
         S.userScroll = false 
    
        mouseEvent = (e)-> 
        S.userScroll = true 
    
        $(document).keydown (e) -> 
        importantKey = (e.which == 33 or  # page up 
         e.which == 34 or # page dn 
         e.which == 32 or # spacebar 
         e.which == 38 or # up 
         e.which == 40 or # down 
         (e.ctrlKey and e.which == 36) or # ctrl + home 
         (e.ctrlKey and e.which == 35) # ctrl + end 
        ) 
        if importantKey 
         S.userScroll = true; 
    
        # Detect user scroll through mouse 
        # Mozilla/Webkit 
        if window.addEventListener 
         document.addEventListener('DOMMouseScroll', mouseEvent, false); 
    
        # for IE/OPERA etc 
        document.onmousewheel = mouseEvent; 
    
    2

    はい、100%可能です。私は現在IEを必要としないアプリケーションでこれを使用しています - クライアントのみが直面しています。私のBackboneアプリケーションがスクロールが変更されたアニメーションを開始すると、スクロールは発生しますが、これらのイベントキャプチャはトリガされません。これはFFでテストされています。Safari &最新のChromeです。

    $('html, body').bind('scroll mousedown wheel DOMMouseScroll mousewheel keyup', function(evt) { 
        // detect only user initiated, not by an .animate though 
        if (evt.type === 'DOMMouseScroll' || evt.type === 'keyup' || evt.type === 'mousewheel') { 
        // up 
        if (evt.originalEvent.detail < 0 || (evt.originalEvent.wheelDelta && evt.originalEvent.wheelDelta > 0)) { 
        // down. 
        } else if (evt.originalEvent.detail > 0 || (evt.originalEvent.wheelDelta && evt.originalEvent.wheelDelta < 0)) { 
        } 
    } 
    }); 
    
    +0

    提案していただきありがとうございます。しかし、これはバイナリソリューションです - javascriptで開始されたスクロール対non-jsスクロールを検出します。私は本当に三項解決策が必要です。 (JavaScript、ユーザー、ブラウザ)。 – mrtsherman

    0

    あなたがJQueryを使用している場合は、より良い答えがあると思われます。明らかに、私は自分自身を試しています。

    は、以下を参照してください。Detect jquery event trigger by user or call by code

    +0

    提案していただきありがとうございます。しかし、これはバイナリソリューションです - javascriptで開始されたスクロール対non-jsスクロールを検出します。私は本当に三項解決策が必要です。 (JavaScript、ユーザー、ブラウザ)。 Sidenoteは、jQueryはあなたのpropsedソリューションの要件ではありません。 – mrtsherman

    0

    することにについて:[戻る]ボタンを使用している場合

    は、具体的には、ブラウザが最後の既知のスクロール位置にジャンプすることがあります。

    ページがレンダリングされた後すぐに起動します。スクロールイベントのリスニングを1秒ほど遅らせることができます。

    +0

    これは堅牢なソリューションではありません。ジャンプする時間はページの読み込み時間に依存します。ブラウザーは、ページが完全に読み込まれるまでジャンプします。これにより、ページの高さ(画像など)が表示されないようにスクロールしないようにするページ要素が表示されなくなります。 – mrtsherman

    0

    すべてのユーザーイベントをキャッチしようとするのではなく、逆の操作を行い、プログラムイベントのみを処理し、それらを無視する方がはるかに簡単です。

    例えば、この種のコードは動作しますが:あなたがsetScrollTop()を呼び出すときに、マウス、キーボード、または他の方法でユーザーのスクロールもしながら

    // Element that needs to be scrolled 
    var myElement = document.getElementById('my-container'); 
    
    // Flag to tell if the change was programmatic or by the user 
    var ignoreNextScrollEvent = false; 
    
    function setScrollTop(scrollTop) { 
        ignoreNextScrollEvent = true; 
        myElement.scrollTop = scrollTop 
    } 
    
    myElement.addEventListener('scroll', function() { 
        if (ignoreNextScrollEvent) { 
         // Ignore this event because it was done programmatically 
         ignoreNextScrollEvent = false; 
         return; 
        } 
    
        // Process user-initiated event here 
    }); 
    

    はその後、スクロールイベントは、無視されますイベントが処理されます。

    関連する問題