web-dev-qa-db-ja.com

onscrollハンドラーをすべてのコンテナーに接続せずに、ページ上のすべてのスクロールイベントをキャプチャする方法

次のWebページを検討してください。

 <html>
   <body onscroll="alert('body scroll event')">
     <div style='width:200px;height:200px;overflow:auto' onscroll="alert('div scroll event')">
       <div style='height:400px'>
       </div>
     </div>
   </body>
 </html>

このHTMLは、スクロールバーを持つdivを作成します。スクロールバーを移動すると、div要素の「onscroll」イベントがトリガーされます。ただし、本体の「オンスクロール」イベントは発生しません。 W3Cでは、要素のonscrollイベントは「バブル」しないと規定されているため、これは予期されています。

ただし、ページの任意の要素のスクロールバーがスクロールされるたびに知る必要があるクライアント側のWebフレームワークを開発しています。 「オンスクロール」がバブルした場合、これは簡単ですが、残念ながらそうではありません。ページ全体でオンスクロールイベントを検出する他の方法はありますか? (現在、私は主にWebkitに焦点を当てているので、Webkit固有のソリューションで問題ありません...)

私が試したいくつかのことを以下に示します。1. DOMAttrModifiedのキャプチャ(スクロールバーの移動に対して起動しないようです。)2. DOMオブザーバーの使用(スクロールバーに対しても起動しないようです)バブリングする(できないようです)

Onscrollイベントをグローバルにキャプチャする唯一の方法は、スクロールする可能性のあるすべての要素にonscrollイベントをアタッチすることです。これは非常にいため、フレームワークのパフォーマンスを低下させます。

誰もがより良い方法を知っていますか?

前もって感謝します!

28
drcode

最新のブラウザですべてのスクロールイベントを検出する最も簡単な方法は、イベントをアタッチするときに「バブル」ではなく「キャプチャ」を使用することです。

window.addEventListener('scroll', function(){ code goes here }, true)

残念ながら、<= IE8などの古いブラウザには同等のものはありません

54
Norman Xu

* ...クリケットの鳴き声... *

OK、この質問はstackoverflowの愛を得るものではないと思うので、他のユーザーがこの質問に出くわした場合に備えて、私がこれまでに見つけた最良の解決策について自分の質問に回答することもできます:

私が思いついた最善の解決策は、BODY要素の「onmousedown」と「onkeydown」をキャプチャすることです。これらのイベントはバブルし、ユーザーがページ上のスクロールバーを移動しようとすると、これらのグローバル関数製品。次に、これらの関数でevent.targetを検索し、マウス/キーが再び「アップ」するまで一時的な「オンスクロール」イベントをそれらのオブジェクトにアタッチします。この方法を使用すると、「ハンドラーの膨張」を回避し、すべての「オンスロール」イベントをグローバルにキャプチャできます。 (これは「マウスホイール」スクロールでも機能すると思いますが、その最終的なしわに関する私の研究はまだ保留中です。)

8
drcode

これと同じ問題がありました。

もちろん、最も簡単な方法はjQueryを使用することです。 この方法は潜在的にあなたのページを遅くする可能性があることに注意してください大幅に。また、イベントのバインド後に追加される新しい要素は考慮されません。

$("*").scroll(function(e) {
    // Handle scroll event
});

Vanilla JavaScriptでは、useCapture呼び出しでtrueブール値をaddEventListenerに設定でき、動的に追加される要素を含むすべての要素で起動します。

document.addEventListener('scroll', function(e) {
    // Handle scroll event
}, true);

ただし、これはscrollイベントが実際に発生する前に発生することに注意してください。私が理解しているように、イベントには2つの段階があります。キャプチャフェーズが最初に発生し、ページルート(ownerDocument?)から開始して、イベントが発生した要素までたどります。この後、要素からルートまで戻るバブリングフェーズが続きます。

いくつかの簡単なテストでも、これがjQueryの処理方法であることが示されました(少なくともすべてのページ要素のスクロールを追跡するため)が、100%確信はありません。

これは、Vanilla JavaScriptメソッドを示すJSFiddleです http://jsfiddle.net/0qpq8pcf/

6
Conner H

バックグラウンドで何かがスクロールされた後にダイアログを閉じたい場合、以下がうまく機能します:

var scrollListener = function(e) {
    // TODO: hide dialog
    document.removeEventListener('scroll', scrollListener, true);
};

document.addEventListener('scroll', scrollListener, true);
1
Antwerp Danish