如何使用 HostListener (Angular 7) 从页面上的元素捕获任何滚动事件?
How can I capture any scroll event from an element on the page using HostListener (Angular 7)?
我正在 Angular 7 中制作一个可重复使用的面包屑栏组件。我希望它在页面滚动后隐藏,然后在用户向上滚动时重新出现。
我做了一个附加到引用 offsetParent 的栏本身的指令,以捕获实际滚动的容器的 scrollTop。所有这些代码都有效,但我不确定如何触发 HostListener 以实际 运行 代码。
我将在这个问题的开头加上这样一个事实,即我真的不想必须将指令附加到每个滚动的容器,因为这会降低组件的灵活性。如何捕获页面上的任何滚动事件?下面的代码片段是 HTML 模板和指令。我也不想使用一堆鼠标事件。肯定必须有某种方式来捕获滚动事件或至少使它们冒泡到文档级别。
提前致谢。
import { Directive, HostListener, Output, EventEmitter, ElementRef, Inject } from '@angular/core';
@Directive({
selector: '[scrollListener]'
})
export class ScrollListenerDirective {
previousScrollContainerScrollTop = 0;
@Output() scroll = new EventEmitter<boolean>();
constructor(private el: ElementRef) { }
@HostListener('document:scroll', ['$event'])
onListenerTriggered(): void {
let currentScrollTop: number;
let elementHeight: number;
const scrollContainerScrollTop = this.el.nativeElement.offsetParent.scrollTop;
elementHeight = this.el.nativeElement.offsetHeight;
currentScrollTop = scrollContainerScrollTop;
if (this.previousScrollContainerScrollTop < currentScrollTop && scrollContainerScrollTop > elementHeight + elementHeight) {
this.scroll.emit(true);
} else if (this.previousScrollContainerScrollTop > currentScrollTop && !(scrollContainerScrollTop <= elementHeight)) {
this.scroll.emit(false);
}
this.previousScrollContainerScrollTop = currentScrollTop;
}
}
<ng-container *ngIf="!hide && breadcrumbs && breadcrumbs.length > 1">
<div scrollListener (scroll)="trackScroll($event)" class="breadcrumb-container" [class.scroll-up]="breadcrumbBarHidden" data-id="breadcrumb-navigation">
<div data-id="back-button" class="back-button" (click)="onBackClick()">
<div class="arrow-container">
<mat-icon svgIcon="left"></mat-icon>
</div>
<span>Back</span>
</div>
<div class="crumb-container">
<ng-container *ngFor="let crumb of breadcrumbs; index as i;">
<div class="crumb">
<div class="crumb-label" (click)="onBreadcrumClick(crumb)" [attr.data-id]="'crumb-' + i" [title]="crumb.label">{{crumb.label}}</div>
<div class="chevron-container">
<mat-icon svgIcon="chevron-right"></mat-icon>
</div>
</div>
</ng-container>
</div>
</div>
</ng-container>
我明白了。我最终使用了一个纯 Javascript 事件监听器,它使用事件发射器触发我的函数。效果很好。
import { Directive, HostListener, Output, EventEmitter, ElementRef, Inject } from '@angular/core';
@Directive({
selector: '[ScrollListener]'
})
export class ScrollListenerDirective {
previousScrollContainerScrollTop = 0;
@Output() scroll = new EventEmitter<boolean>();
constructor(private el: ElementRef) {
document.addEventListener('scroll', (event) => {
this.onListenerTriggered(event);
}, true); // This is so we can use a UseCapture event listener. Document scrolls do not bubble back up to the document level
}
onListenerTriggered(event): void {
let currentScrollTop: number;
let elementHeight: number;
const scrollContainerScrollTop = this.el.nativeElement.offsetParent.scrollTop;
elementHeight = this.el.nativeElement.offsetHeight;
currentScrollTop = scrollContainerScrollTop;
if (this.previousScrollContainerScrollTop < currentScrollTop && scrollContainerScrollTop > elementHeight + elementHeight) {
this.scroll.emit(true);
} else if (this.previousScrollContainerScrollTop > currentScrollTop && !(scrollContainerScrollTop <= elementHeight)) {
this.scroll.emit(false);
}
this.previousScrollContainerScrollTop = currentScrollTop;
}
}
我正在 Angular 7 中制作一个可重复使用的面包屑栏组件。我希望它在页面滚动后隐藏,然后在用户向上滚动时重新出现。
我做了一个附加到引用 offsetParent 的栏本身的指令,以捕获实际滚动的容器的 scrollTop。所有这些代码都有效,但我不确定如何触发 HostListener 以实际 运行 代码。
我将在这个问题的开头加上这样一个事实,即我真的不想必须将指令附加到每个滚动的容器,因为这会降低组件的灵活性。如何捕获页面上的任何滚动事件?下面的代码片段是 HTML 模板和指令。我也不想使用一堆鼠标事件。肯定必须有某种方式来捕获滚动事件或至少使它们冒泡到文档级别。
提前致谢。
import { Directive, HostListener, Output, EventEmitter, ElementRef, Inject } from '@angular/core';
@Directive({
selector: '[scrollListener]'
})
export class ScrollListenerDirective {
previousScrollContainerScrollTop = 0;
@Output() scroll = new EventEmitter<boolean>();
constructor(private el: ElementRef) { }
@HostListener('document:scroll', ['$event'])
onListenerTriggered(): void {
let currentScrollTop: number;
let elementHeight: number;
const scrollContainerScrollTop = this.el.nativeElement.offsetParent.scrollTop;
elementHeight = this.el.nativeElement.offsetHeight;
currentScrollTop = scrollContainerScrollTop;
if (this.previousScrollContainerScrollTop < currentScrollTop && scrollContainerScrollTop > elementHeight + elementHeight) {
this.scroll.emit(true);
} else if (this.previousScrollContainerScrollTop > currentScrollTop && !(scrollContainerScrollTop <= elementHeight)) {
this.scroll.emit(false);
}
this.previousScrollContainerScrollTop = currentScrollTop;
}
}
<ng-container *ngIf="!hide && breadcrumbs && breadcrumbs.length > 1">
<div scrollListener (scroll)="trackScroll($event)" class="breadcrumb-container" [class.scroll-up]="breadcrumbBarHidden" data-id="breadcrumb-navigation">
<div data-id="back-button" class="back-button" (click)="onBackClick()">
<div class="arrow-container">
<mat-icon svgIcon="left"></mat-icon>
</div>
<span>Back</span>
</div>
<div class="crumb-container">
<ng-container *ngFor="let crumb of breadcrumbs; index as i;">
<div class="crumb">
<div class="crumb-label" (click)="onBreadcrumClick(crumb)" [attr.data-id]="'crumb-' + i" [title]="crumb.label">{{crumb.label}}</div>
<div class="chevron-container">
<mat-icon svgIcon="chevron-right"></mat-icon>
</div>
</div>
</ng-container>
</div>
</div>
</ng-container>
我明白了。我最终使用了一个纯 Javascript 事件监听器,它使用事件发射器触发我的函数。效果很好。
import { Directive, HostListener, Output, EventEmitter, ElementRef, Inject } from '@angular/core';
@Directive({
selector: '[ScrollListener]'
})
export class ScrollListenerDirective {
previousScrollContainerScrollTop = 0;
@Output() scroll = new EventEmitter<boolean>();
constructor(private el: ElementRef) {
document.addEventListener('scroll', (event) => {
this.onListenerTriggered(event);
}, true); // This is so we can use a UseCapture event listener. Document scrolls do not bubble back up to the document level
}
onListenerTriggered(event): void {
let currentScrollTop: number;
let elementHeight: number;
const scrollContainerScrollTop = this.el.nativeElement.offsetParent.scrollTop;
elementHeight = this.el.nativeElement.offsetHeight;
currentScrollTop = scrollContainerScrollTop;
if (this.previousScrollContainerScrollTop < currentScrollTop && scrollContainerScrollTop > elementHeight + elementHeight) {
this.scroll.emit(true);
} else if (this.previousScrollContainerScrollTop > currentScrollTop && !(scrollContainerScrollTop <= elementHeight)) {
this.scroll.emit(false);
}
this.previousScrollContainerScrollTop = currentScrollTop;
}
}