我似乎无法捕获窗口滚动事件。 在几个网站上,我发现了与此类似的代码:
@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);
}