Heim > Web-Frontend > js-Tutorial > Hauptteil

Angular LAB: Lassen Sie uns eine Sichtbarkeitsanweisung erstellen

Barbara Streisand
Freigeben: 2024-10-09 08:21:02
Original
849 Leute haben es durchsucht

Angular LAB: let

In diesem Artikel werde ich veranschaulichen, wie man eine sehr einfache Angular-Direktive erstellt, die den Sichtbarkeitsstatus eines Elements verfolgt, oder mit anderen Worten, wann es ein- und ausgeht das Ansichtsfenster. Ich hoffe, das wird eine schöne und vielleicht nützliche Übung!

Dazu verwenden wir die IntersectionObserver-JavaScript-API, die in modernen Browsern verfügbar ist.

Was wir erreichen wollen

Wir möchten die Richtlinie wie folgt verwenden:

<p
  visibility
  [visibilityMonitor]="true"
  (visibilityChange)="onVisibilityChange($event)"
>
  I'm being observed! Can you see me yet?
</p>
Nach dem Login kopieren
  • Sichtbarkeit ist der Selektor unserer benutzerdefinierten Direktive
  • VisibilityMonitor ist eine optionale Eingabe, die angibt, ob das Element weiterhin beobachtet werden soll oder nicht (falls falsch, wird die Überwachung beendet, wenn es in das Ansichtsfenster eintritt)
  • VisibilityChange benachrichtigt uns

Die Ausgabe hat folgende Form:

type VisibilityChange =
  | {
      isVisible: true;
      target: HTMLElement;
    }
  | {
      isVisible: false;
      target: HTMLElement | undefined;
    };
Nach dem Login kopieren

Ein undefiniertes Ziel bedeutet, dass das Element aus dem DOM entfernt wurde (z. B. durch ein @if).

Erstellung der Richtlinie

Unsere Direktive überwacht lediglich ein Element, sie ändert nicht die DOM-Struktur: Es handelt sich um eine Attribut-Direktive.

@Directive({
  selector: "[visibility]",
  standalone: true
})
export class VisibilityDirective implements OnInit, OnChanges, AfterViewInit, OnDestroy {
  private element = inject(ElementRef);

  /**
   * Emits after the view is initialized.
   */
  private afterViewInit$ = new Subject<void>();

  /**
   * The IntersectionObserver for this element.
   */
  private observer: IntersectionObserver | undefined;

  /**
   * Last known visibility for this element.
   * Initially, we don't know.
   */
  private isVisible: boolean = undefined;

  /**
   * If false, once the element becomes visible there will be one emission and then nothing.
   * If true, the directive continuously listens to the element and emits whenever it becomes visible or not visible.
   */
  visibilityMonitor = input(false);

  /**
   * Notifies the listener when the element has become visible.
   * If "visibilityMonitor" is true, it continuously notifies the listener when the element goes in/out of view.
   */
  visibilityChange = output<VisibilityChange>();
}
Nach dem Login kopieren

Im Code oben sehen Sie:

  • die Eingabe und Ausgabe, über die wir zuvor gesprochen haben
  • eine Eigenschaft namens afterViewInit$ (ein Observable), die als reaktives Gegenstück zum ngAfterViewInit-Lebenszyklus-Hook fungiert
  • Eine Eigenschaft namens Observer, die den IntersectionObserver speichert, der für die Überwachung unseres Elements verantwortlich ist
  • eine Eigenschaft namens isVisibile, die den letzten Sichtbarkeitsstatus speichert, um zu vermeiden, dass derselbe Status zweimal hintereinander erneut ausgegeben wird

Und natürlich fügen wir die ElementRef ein, um das DOM-Element zu erfassen, auf das wir unsere Direktive anwenden.

Bevor wir die Hauptmethode schreiben, kümmern wir uns um den Lebenszyklus der Direktive.

ngOnInit(): void {
  this.reconnectObserver();
}

ngOnChanges(): void {
  this.reconnectObserver();
}

ngAfterViewInit(): void {
  this.afterViewInit$.next();
}

ngOnDestroy(): void {
  // Disconnect and if visibilityMonitor is true, notify the listener
  this.disconnectObserver();
  if (this.visibilityMonitor) {
    this.visibilityChange.emit({
      isVisible: false,
      target: undefined
    });
  }
}

private reconnectObserver(): void {}
private disconnectObserver(): void {}
Nach dem Login kopieren

Jetzt passiert Folgendes:

  • Innerhalb von ngOnInit und ngOnChanges starten wir den Beobachter neu. Dies dient dazu, die Direktive reaktiv zu machen: Wenn sich die Eingabe ändert, verhält sich die Direktive anders. Beachten Sie, dass wir, selbst wenn ngOnChanges auch vor ngOnInit ausgeführt wird, immer noch ngOnInit benötigen, da ngOnChanges nicht ausgeführt wird, wenn in der Vorlage keine Eingaben vorhanden sind!
  • Wenn die Ansicht initialisiert ist, lösen wir den Betreff aus, wir werden in ein paar Sekunden dazu gelangen
  • Wir trennen unseren Beobachter, wenn die Direktive zerstört wird, um Speicherlecks zu vermeiden. Wenn der Entwickler schließlich darum bittet, benachrichtigen wir ihn, dass das Element aus dem DOM entfernt wurde, indem wir ein undefiniertes Element ausgeben.

IntersectionObserver

Das ist der Kern unserer Richtlinie. Unsere reconnectObserver-Methode wird diejenige sein, die mit der Beobachtung beginnt! Es wird ungefähr so ​​aussehen:

private reconnectObserver(): void {
    // Disconnect an existing observer
    this.disconnectObserver();
    // Sets up a new observer
    this.observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        const { isIntersecting: isVisible, target } = entry;
        const hasChangedVisibility = isVisible !== this.isVisible;
        const shouldEmit = isVisible || (!isVisible && this.visibilityMonitor);
        if (hasChangedVisibility && shouldEmit) {
          this.visibilityChange.emit({
            isVisible,
            target: target as HTMLElement
          });
          this.isVisible = isVisible;
        }
        // If visilibilyMonitor is false, once the element is visible we stop.
        if (isVisible && !this.visibilityMonitor) {
          observer.disconnect();
        }
      });
    });
    // Start observing once the view is initialized
    this.afterViewInit$.subscribe(() => {
        this.observer?.observe(this.element.nativeElement);
    });
  }
Nach dem Login kopieren

Vertrauen Sie mir, es ist nicht so kompliziert, wie es scheint! Hier ist der Mechanismus:

  • Zuerst trennen wir den Beobachter, wenn er bereits ausgeführt wurde
  • Wir erstellen einen IntersectionObserver und definieren sein Verhalten. Die Einträge enthalten die überwachten Elemente, also unser Element. Die Eigenschaft isIntersecting zeigt an, ob sich die Sichtbarkeit des Elements geändert hat: Wir vergleichen es mit dem vorherigen Status (unserer Eigenschaft) und geben es aus, wenn es fällig ist. Anschließend speichern wir den neuen Zustand in unserem Eigentum für später.
  • Wenn „visibilityMonitor“ falsch ist, trennen wir den Beobachter, sobald das Element sichtbar wird: Seine Aufgabe ist erledigt!
  • Dann müssen wir den Beobachter starten, indem wir unser Element passieren, also warten wir darauf, dass unsere Ansicht initialisiert wird, um das zu tun.

Zuletzt implementieren wir die Methode, die den Beobachter ganz einfach abkoppelt:

 private disconnectObserver(): void {
    if (this.observer) {
      this.observer.disconnect();
      this.observer = undefined;
    }
  }
Nach dem Login kopieren

Endgültiger Code

Hier ist die vollständige Richtlinie. Dies war nur eine Übung, Sie können sie also beliebig ändern!

type VisibilityChange =
  | {
      isVisible: true;
      target: HTMLElement;
    }
  | {
      isVisible: false;
      target: HTMLElement | undefined;
    };

@Directive({
  selector: "[visibility]",
  standalone: true
})
export class VisibilityDirective
  implements OnChanges, OnInit, AfterViewInit, OnDestroy {
  private element = inject(ElementRef);

  /**
   * Emits after the view is initialized.
   */
  private afterViewInit$ = new Subject();

  /**
   * The IntersectionObserver for this element.
   */
  private observer: IntersectionObserver | undefined;

  /**
   * Last known visibility for this element.
   * Initially, we don't know.
   */
  private isVisible: boolean = undefined;

  /**
   * If false, once the element becomes visible there will be one emission and then nothing.
   * If true, the directive continuously listens to the element and emits whenever it becomes visible or not visible.
   */
  visibilityMonitor = input(false);

  /**
   * Notifies the listener when the element has become visible.
   * If "visibilityMonitor" is true, it continuously notifies the listener when the element goes in/out of view.
   */
  visibilityChange = output();

  ngOnInit(): void {
    this.reconnectObserver();
  }

  ngOnChanges(): void {
    this.reconnectObserver();
  }

  ngAfterViewInit(): void {
    this.afterViewInit$.next(true);
  }

  ngOnDestroy(): void {
    // Disconnect and if visibilityMonitor is true, notify the listener
    this.disconnectObserver();
    if (this.visibilityMonitor) {
      this.visibilityChange.emit({
        isVisible: false,
        target: undefined
      });
    }
  }

  private reconnectObserver(): void {
    // Disconnect an existing observer
    this.disconnectObserver();
    // Sets up a new observer
    this.observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        const { isIntersecting: isVisible, target } = entry;
        const hasChangedVisibility = isVisible !== this.isVisible;
        const shouldEmit = isVisible || (!isVisible && this.visibilityMonitor);
        if (hasChangedVisibility && shouldEmit) {
          this.visibilityChange.emit({
            isVisible,
            target: target as HTMLElement
          });
          this.isVisible = isVisible;
        }
        // If visilibilyMonitor is false, once the element is visible we stop.
        if (isVisible && !this.visibilityMonitor) {
          observer.disconnect();
        }
      });
    });
    // Start observing once the view is initialized
    this.afterViewInit$.subscribe(() => {
        this.observer?.observe(this.element.nativeElement);
    });
  }

  private disconnectObserver(): void {
    if (this.observer) {
      this.observer.disconnect();
      this.observer = undefined;
    }
  }
}
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonAngular LAB: Lassen Sie uns eine Sichtbarkeitsanweisung erstellen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!