可能你document
不是在滚动,而是在div
里面。window
如果从 调用滚动事件,它只会冒泡到document
。此外,如果您从中捕获事件document
并调用类似的方法stopPropagation
,您将不会在window
.
如果要捕获应用程序中的所有滚动事件,这些事件也来自可滚动的小容器,则必须使用默认addEventListener
方法useCapture
set to true
。
当它下降到DOM
, 而不是气泡阶段时,这将触发事件。不幸的是,坦率地说,这是一个很大的失误,angular 没有提供传递事件侦听器选项的选项,因此您必须使用addEventListener
:
export class WindowScrollDirective {
ngOnInit() {
window.addEventListener('scroll', this.scroll, true); //third parameter
}
ngOnDestroy() {
window.removeEventListener('scroll', this.scroll, true);
}
scroll = (event): void => {
//handle your scroll here
//notice the 'odd' function assignment to a class field
//this is used to be able to remove the event listener
};
}
现在这还不是全部,因为所有主要浏览器(显然,IE 和 Edge 除外)都实现了新addEventListener
规范,这使得将对象作为第三个参数传递成为可能。
使用此对象,您可以将事件侦听器标记为passive
。这是对触发大量时间的事件的推荐做法,这会干扰 UI 性能,例如滚动事件。要实现这一点,您应该首先检查当前浏览器是否支持此功能。在 mozilla.org 上,他们发布了一个方法passiveSupported
,您可以使用该方法检查浏览器支持。但是,您只能在确定不会使用时使用它event.preventDefault()
在我向您展示如何做到这一点之前,您可以想到另一个性能特性。为了防止运行更改检测(DoCheck
每次在区域内发生异步事件时都会调用它。就像事件触发一样),您应该在区域外运行您的事件侦听器,并且仅在确实需要时才输入它。Soo,让我们把所有这些东西结合起来:
export class WindowScrollDirective {
private eventOptions: boolean|{capture?: boolean, passive?: boolean};
constructor(private ngZone: NgZone) {}
ngOnInit() {
if (passiveSupported()) { //use the implementation on mozilla
this.eventOptions = {
capture: true,
passive: true
};
} else {
this.eventOptions = true;
}
this.ngZone.runOutsideAngular(() => {
window.addEventListener('scroll', this.scroll, <any>this.eventOptions);
});
}
ngOnDestroy() {
window.removeEventListener('scroll', this.scroll, <any>this.eventOptions);
//unfortunately the compiler doesn't know yet about this object, so cast to any
}
scroll = (): void => {
if (somethingMajorHasHappenedTimeToTellAngular) {
this.ngZone.run(() => {
this.tellAngular();
});
}
};
}