如何在Angular 4中处理窗口滚动事件?

时间:2017-06-13 08:23:23

标签: angular typescript scroll

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

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

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

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

7 个答案:

答案 0 :(得分:60)

您的document可能不会滚动,但其中只有div。如果从window调用滚动事件,则仅向document冒泡。此外,如果您从document抓取活动并拨打stopPropagation,则您将无法在window收到该活动。

如果要捕获应用程序中的所有滚动事件(也是来自微小的可滚动容器),则必须使用默认的addEventListener方法,并将useCapture设置为true

当事件发生在DOM,而不是泡沫阶段时,这将触发事件。不幸的是,坦率地说,一个很大的错过,angular不提供传递事件监听器选项的选项,所以你必须使用addEventListener

export class WindowScrollDirective {

    ngOnInit() {
        window.addEventListener('scroll', this.scroll, true); //third parameter
    }

    ngOnDestroy() {
        window.removeEventListener('scroll', this.scroll, true);
    }

    scroll = (): 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传递。

使用此对象,您可以将事件侦听器标记为passive。对于会激活大量时间的事件,这是一个建议的事情,这会干扰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();
           });
        }
    };   
}

答案 1 :(得分:9)

如果您恰巧是 使用角材料 ,则可以执行以下操作:

import { ScrollDispatchModule } from '@angular/cdk/scrolling';

在Ts:

import { ScrollDispatcher } from '@angular/cdk/scrolling';

  constructor(private scrollDispatcher: ScrollDispatcher) {    
    this.scrollDispatcher.scrolled().subscribe(x => console.log('I am scrolling'));
  }

在模板中:

<div cdkScrollable>
  <div *ngFor="let one of manyToScrollThru">
    {{one}}
  </div>
</div>

参考:https://material.angular.io/cdk/scrolling/overview

答案 2 :(得分:4)

我还没有评论。 @PierreDuc是您的答案,除非@Robert表示文档不会滚动。我对您的答案做了一些修改,以使用侦听器发送的事件,然后监视源元素。

 ngOnInit() {
    window.addEventListener('scroll', this.scrollEvent, true);
  }

  ngOnDestroy() {
    window.removeEventListener('scroll', this.scrollEvent, true);
  }

  scrollEvent = (event: any): void => {
    const number = event.srcElement.scrollTop;
  }

答案 3 :(得分:1)

在角度8中,实现此代码,以我为例,它可以正常使用滚动来更改导航栏的颜色... 您的模板:

<div class="level" (scroll)="scrolling($event)"  [ngClass]="{'level-trans': scroll}">
<!-- your template -->
</div>

您的.ts

export class HomeNavbarComponent implements OnInit {

  scroll:boolean=false;
  constructor() { }

  ngOnInit() {
    window.addEventListener('scroll', this.scrolling, true)
  }
  scrolling=(s)=>{
    let sc = s.target.scrollingElement.scrollTop;
    console.log();
    if(sc >=100){this.scroll=true}
    else{this.scroll=false}
  }

您的CSS

.level{
    width: 100%;
    height: 57px;
    box-shadow: 0 0 5px 0 rgba(0, 0,0,0.7);
    background: transparent;
    display: flex;
    position: fixed;
    top: 0;
    z-index: 5;
    transition: .8s all ease;
}
.level-trans{
    background: whitesmoke;
}

答案 4 :(得分:1)

以防万一我想捕捉一个没有滚动条的无法滚动的元素上的滚轮动作...

所以,我需要的是这个

@HostListener('mousewheel', ['$event']) 
onMousewheel(event) {
     console.log(event)
}

答案 5 :(得分:0)

@PierreDuc感谢您的回答。

Improving scrolling performance with passive listeners中所述 有关MDN的部分:

  

您无需担心 被动 的价值   滚动事件。由于无法取消,因此事件监听器无法阻止   页面呈现。

就我而言,只需将 true 作为 window.addEventListener 函数的第三个参数传递,就可以简化您的答案。

答案 6 :(得分:0)

我不知道我是否遗漏了什么......因为我遇到了同样的问题(即使今天 [2021] 也无法在网上的任何地方找到任何答案)但后来只是尝试将“window”替换为“body” "而且它工作得很好(代码少了很多)。

代码片段(就我而言,添加到我的导航栏组件中):

  @HostListener('body:scroll', ['$event'])
  public onScrollingEvent(): void {
    console.log('Currently scrolling');
    this.navbarClass = ['nav', 'add-shadow'];
  }

希望同一地点的其他人能找到这个,让他们的生活更轻松!

相关问题