如何捕获页面上的所有滚动事件而不将onscroll处理程序附加到每个容器

drc*_*ode 30 javascript dom scroll javascript-events

请考虑以下网页:

 <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>
Run Code Online (Sandbox Code Playgroud)

这个html创建一个带滚动条的div.如果移动滚动条,则会触发div元素上的"onscroll"事件.但是,身体上的"onscroll"事件不会被触发.这是预期的,因为W3C声明元素onscroll事件不会"冒泡".

但是,我正在开发一个客户端Web框架,只要滚动页面的任何元素上的滚动条,就需要知道它.如果"onscroll"冒泡,这很容易做到,但不幸的是,它没有.有没有其他方法可以检测整个页面上的onscroll事件?(现在我主要关注Webkit,所以特定于Webkit的解决方案会很好......)

以下是我尝试过的一些事情:1.捕获DOMAttrModified(似乎不会触发移动滚动条.)2.使用DOM Observers(似乎也不会触发滚动条)3.更改"onscroll"事件类型泡沫(似乎不可能)

似乎全局捕获onscroll事件的唯一方法是将onscroll事件附加到可能滚动的每个元素,这非常难看并且会损害我的框架的性能.

谁知道更好的方法?

提前致谢!

Nor*_* Xu 59

在现代浏览器中检测所有滚动事件的最简单方法是在附加事件时使用"捕获"而不是"冒泡":

window.addEventListener('scroll', function(){ code goes here }, true)
Run Code Online (Sandbox Code Playgroud)

不幸的是,我知道在旧的浏览器中没有等效的,例如<= IE8

  • 非常感谢这一点 (3认同)

drc*_*ode 8

*...蟋蟀唧唧喳喳...*

好吧,我想这个问题不会得到任何stackoverflow的爱,所以我不妨回答我自己的问题,到目前为止我找到的最佳解决方案,万一其他用户偶然发现这个问题:

我提出的最佳解决方案是捕获BODY元素的"onmousedown"和"onkeydown":这些事件会冒泡,因此如果用户试图在页面上移动滚动条,这些全局函数将作为以下内容触发:产品.然后,在这些函数中,只需查找event.target并将临时"onscroll"事件附加到这些对象,直到鼠标/键再次"向上".使用该方法,您可以避免"处理程序膨胀"并仍然全局捕获所有"onscroll"事件.(我认为这也适用于"鼠标滚轮"滚动,但我对最终皱纹的研究仍在进行中.)


Con*_*r H 6

我有同样的问题.

最简单的方法当然是使用jQuery.请注意,此方法可能会显着降低您的网页速度.此外,它不会考虑绑定事件后添加的任何新元素.

$("*").scroll(function(e) {
    // Handle scroll event
});
Run Code Online (Sandbox Code Playgroud)

在vanilla JavaScript中,您可以在调用时设置useCapture布尔值,它将触发所有元素,包括动态添加的元素.trueaddEventListener

document.addEventListener('scroll', function(e) {
    // Handle scroll event
}, true);
Run Code Online (Sandbox Code Playgroud)

请注意,这将在滚动事件实际发生之前触发.据我所知,有两个阶段的事件经历.捕获阶段首先发生,并从页面根目录(ownerDocument?)开始,然后遍历到发生事件的元素.在此之后出现鼓泡阶段,从元素返回到根部.

一些快速测试也表明这可能是jQuery处理它的方式(至少跟踪所有页面元素上的滚动),但我不是100%肯定.

这是一个显示vanilla JavaScript方法的JSFiddle http://jsfiddle.net/0qpq8pcf/

  • 小心第一种方法,因为将事件侦听器附加到每个单独的DOM元素可能会使事情变得非常缓慢(更不用说这不会考虑创建事件处理程序后添加的元素).第二种可能更可取,但是如果可能的话,你也应该在不需要的时候删除它(例如,如果你只想让它知道何时解除弹出窗口或其他东西,只在弹出窗口打开时附加它并在弹出窗口时删除它关闭). (3认同)