【问题标题】:How can I capture any scroll event from an element on the page using HostListener (Angular 7)?如何使用 HostListener (Angular 7) 从页面上的元素捕获任何滚动事件?
【发布时间】:2020-02-18 20:14:25
【问题描述】:

我正在 Angular 7 中制作一个可重用的面包屑栏组件。我希望它在页面滚动一点后隐藏,然后在用户向上滚动时重新出现。

我做了一个指令来附加到引用 offsetParent 的栏本身以捕获实际滚动的容器的 scrollTop。所有这些代码都有效,但我不确定如何触发 HostListener 来实际运行代码。

我将在这个问题的开头说明我真的不想为每个滚动的容器附加一个指令,因为这会降低组件的灵活性。如何捕获页面上的任何滚动事件?下面的代码 sn-p 是 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>

【问题讨论】:

  • 希望这篇帖子 stackoverflow.com/questions/44337691/…能有所帮助
  • 我的实际隐藏面包屑栏的代码有效。我正在尝试找到一种方法来触发 HostListener 而不向每个滚动的容器附加指令。我可以使用 UseCapture 和纯 JavaScript 事件侦听器来做到这一点,但是我不能在指令中使用输出发射器。

标签: angular typescript user-interface scroll angular7


【解决方案1】:

我想通了。我最终使用了一个纯 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;

  }
}

【讨论】:

    猜你喜欢
    • 2016-12-09
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 2019-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多