javascript - 如何处理 Angular 4 中的窗口滚动事件?

标签 javascript angular typescript

我似乎无法捕获窗口滚动事件。 在几个网站上,我发现了类似这样的代码:

@HostListener("window:scroll", [])
onWindowScroll() {
  console.log("Scrolling!");
}

这些片段通常来自版本 2。这在 Angular 4.2.2 中似乎不起作用(不再?)。例如,如果我将“window:scroll”替换为“window:touchmove”,那么 touchmove 事件就会得到很好的处理。

有人知道我错过了什么吗?非常感谢!

最佳答案

可能您的 document 没有滚动,但其中的 div 可以滚动。如果从 document 调用滚动事件,它只会冒泡到 window。此外,如果您从 document 捕获事件并调用类似 stopPropagation 的方法,您将不会在 window 中接收到该事件。

如果您想捕获应用程序中的所有滚动事件,这些滚动事件也将来自微小的可滚动容器,您必须使用默认的 addEventListener 方法并设置 useCapturetrue

这将在它进入 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 规范,这使得可以将对象作为 third parameter 传递。

使用此对象,您可以将事件监听器标记为被动。建议对触发时间较长的事件执行此操作,这会干扰 UI 性能,例如滚动事件。要实现这一点,您应该首先检查当前浏览器是否支持此功能。在 mozilla.org 上,他们发布了一个方法 passiveSupported,您可以使用它检查浏览器支持。不过,您只能在确定不会使用 event.preventDefault()

时使用它

在我向您展示如何做到这一点之前,您可以想到另一个性能特征。为防止更改检测运行(每次区域内发生异步事件时都会调用 DoCheck。例如事件触发),您应该在区域外运行事件监听器,并且仅在真正发生时才进入它必要的。那么,让我们结合所有这些东西:

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();
           });
        }
    };   
}

关于javascript - 如何处理 Angular 4 中的窗口滚动事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44516017/

相关文章:

javascript - 在具有相同配置的多个 Angular 应用程序中外部化服务配置

javascript - 如何在 contenteditable div 中创建一个段落?

angular - 将 Tradingview 嵌入 Angular 5

Angular2 + webpack 不部署robots.txt

typescript - `yield call` 的返回类型

typescript - Redux Sagas、TypeScript 和调用?

javascript - Rails 5 - 将表单提交结果渲染为 js 或其他格式(例如 PDF)

javascript - 使用 Sinon 在 D3 中测试鼠标悬停事件

angular - ionic2 rc0 中找不到组件工厂错误

javascript - 类型错误 : Cannot assign to read only property 'performance' of object '[object global]'