如何使用 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;

  }
}