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



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

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

代码段通常来自版本 2。这似乎在 Angular 4.2.2 中不起作用(不再?例如,如果我将"窗口:滚动"替换为"窗口:触摸移动",那么触摸移动事件就可以处理。

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

可能你的document没有滚动,但里面的div在滚动。仅当从document调用滚动事件时,滚动事件才会冒泡到window。此外,如果您从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 = (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。就像事件触发一样),您应该在区域之外运行事件侦听器,并且仅在真正需要时才输入它。因此,让我们将所有这些内容结合起来:

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 Material,你可以这样做:

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

我还不能发表评论。 @PierreDuc你的答案是正确的,除了@Robert说文档不滚动。我稍微修改了一下您的答案以使用侦听器发送的事件,然后监视源元素。

ngOnInit() {
window.addEventListener('scroll', this.scrollEvent, true);
}
ngOnDestroy() {
window.removeEventListener('scroll', this.scrollEvent, true);
}
scrollEvent = (event: any): void => {
const n = event.srcElement.scrollingElement.scrollTop;
}

在 angular 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;
}

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

所以,我需要的是这个:

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

HostListener中带有window的替代方案: 使用body

core.d.ts

可用于为事件名称添加前缀的全局目标名称是document:window:body:

@HostListener('body:scroll', ['$event']) onScroll(event: any) {
console.log(event);
}

最新更新