Dalam artikel ini saya akan menggambarkan cara mencipta Arahan Sudut yang sangat mudah yang menjejaki keadaan keterlihatan elemen, atau dengan kata lain, apabila ia masuk dan keluar dari tempat pandang. Saya harap ini akan menjadi latihan yang bagus dan mungkin berguna!
Untuk melakukan ini, kami akan menggunakan IntersectionObserver JavaScript API yang tersedia dalam penyemak imbas moden.
Kami mahu menggunakan Arahan seperti ini:
<p visibility [visibilityMonitor]="true" (visibilityChange)="onVisibilityChange($event)" > I'm being observed! Can you see me yet? </p>
Output akan dalam bentuk ini:
type VisibilityChange = | { isVisible: true; target: HTMLElement; } | { isVisible: false; target: HTMLElement | undefined; };
Mempunyai sasaran yang tidak ditentukan bermakna elemen telah dialih keluar daripada DOM (contohnya, oleh @if).
Arahan kami hanya akan memantau elemen, ia tidak akan mengubah struktur DOM: ia akan menjadi Arahan Atribut.
@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>(); }
Dalam kod di atas anda lihat:
Dan secara semulajadi, kami menyuntik ElementRef untuk mendapatkan elemen DOM yang kami gunakan arahan kami.
Sebelum menulis kaedah utama, mari kita jaga kitaran hayat arahan.
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 {}
Sekarang inilah yang berlaku:
Ini adalah inti dari arahan kami. Kaedah reconnectObserver kami akan mula memerhati! Ia akan menjadi seperti ini:
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); }); }
Percayalah, ia tidaklah serumit yang kelihatan! Inilah mekanismenya:
Akhir sekali, mari kita laksanakan kaedah yang memutuskan sambungan pemerhati, easy peasy:
private disconnectObserver(): void { if (this.observer) { this.observer.disconnect(); this.observer = undefined; } }
Ini arahan penuh. Ini hanyalah latihan, jadi bebas untuk menukarnya kepada apa sahaja yang anda suka!
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; } } }
Atas ialah kandungan terperinci Angular LAB: mari buat Arahan Keterlihatan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!