可能是你的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();
});
}
};
}