TypeScript - איך אני יכול ללכוד כל אירוע גלילה מאלמנט בעמוד באמצעות 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>

תשובה #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;

  }
}