Как я могу захватить любое событие прокрутки от элемента на странице, используя HostListener (Angular 7)? - PullRequest
2 голосов
/ 22 октября 2019

Я делаю многократно используемый компонент батончика в 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>

1 Ответ

0 голосов
/ 24 октября 2019

Я понял это. В итоге я использовал чистый слушатель событий 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;

  }
}
...