如何在 Angular 4 中处理窗口滚动事件? [英] How to handle window scroll event in Angular 4?

查看:32
本文介绍了如何在 Angular 4 中处理窗口滚动事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎无法捕获 Window 滚动事件.在几个网站上,我发现了与此类似的代码:

I can't seem to be able to capture the Window scroll event. On several sites I found code similar to this:

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

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

The snippets often come from version 2. This doesn't seem to work (anymore?) in Angular 4.2.2. If I replace "window:scroll" with "window:touchmove" for example, then then touchmove event is handled fine.

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

Does anyone know what I'm missing? Thank you very much!

推荐答案

可能你的 document 没有滚动,但是它里面的 div 是滚动的.如果滚动事件是从 document 调用的,它只会冒泡到 window.此外,如果您从 document 捕获事件并调用诸如 stopPropagation 之类的东西,您将不会在 window 中收到该事件.

Probably your document isn't scrolling, but a div inside it is. The scroll event only bubbles up to the window if it's called from document. Also if you capture the event from document and call something like stopPropagation, you will not receive the event in window.

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

If you want to capture all the scroll events inside your application, which will also be from tiny scrollable containers, you have to use the default addEventListener method with useCapture set to true.

当它沿着 DOM 而不是冒泡阶段时,这将触发事件.不幸的是,坦率地说,这是一个很大的失误,angular 没有提供传递事件侦听器选项的选项,因此您必须使用 addEventListener:

This will fire the event when it goes down the DOM, instead of the bubble stage. Unfortunately, and quite frankly a big miss, angular does not provide an option to pass in the event listener options, so you have to use the 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 规范,这使得可以将对象作为 第三个参数.

Now this is not all there is to it, because all major browsers (except IE and Edge, obviously) have implemented the new addEventListener spec, which makes it possible to pass an object as third parameter.

使用此对象,您可以将事件侦听器标记为 passive.这是对触发大量时间的事件的推荐做法,这会干扰 UI 性能,例如滚动事件.要实现这一点,您应该首先检查当前浏览器是否支持此功能.在 mozilla.org 上,他们发布了一个方法 passiveSupported,您可以使用该方法检查浏览器支持.你只能使用它,当你确定你不会使用 event.preventDefault()

With this object you can mark an event listener as passive. This is a recommend thing to do on an event which fires a lot of time, which can interfere with UI performance, like the scroll event. To implement this, you should first check if the current browser supports this feature. On the mozilla.org they've posted a method passiveSupported, with which you can check for browser support. You can only use this though, when you are sure you are not going to use event.preventDefault()

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

Before I show you how to do that, there is another performance feature you could think of. To prevent change detection from running (the DoCheck gets called every time something async happens within the zone. Like an event firing), you should run your event listener outside the zone, and only enter it when it's really necessary. Soo, let's combine all these things:

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

这篇关于如何在 Angular 4 中处理窗口滚动事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆