이 기사에서는 요소의 가시성 상태, 즉 요소가 들어오고 나갈 때를 추적하는 매우 간단한 Angular 지시문을 만드는 방법을 설명하겠습니다. 뷰포트. 이것이 훌륭하고 유용한 연습이 되기를 바랍니다!
이를 위해 최신 브라우저에서 사용할 수 있는 IntersectionObserver JavaScript API를 사용할 것입니다.
우리는 다음과 같이 지시어를 사용하고 싶습니다:
<p visibility [visibilityMonitor]="true" (visibilityChange)="onVisibilityChange($event)" > I'm being observed! Can you see me yet? </p>
출력은 다음과 같습니다.
type VisibilityChange = | { isVisible: true; target: HTMLElement; } | { isVisible: false; target: HTMLElement | undefined; };
정의되지 않은 대상이 있다는 것은 요소가 DOM에서 제거되었음을 의미합니다(예: @if에 의해).
우리 지시어는 단순히 요소를 모니터링할 뿐 DOM 구조를 변경하지 않습니다. 속성 지시어가 됩니다.
@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>(); }
위 코드에는 다음이 표시됩니다.
그리고 당연히 지시어를 적용할 DOM 요소를 가져오기 위해 ElementRef를 삽입합니다.
메인 메소드를 작성하기 전에 디렉티브의 라이프사이클을 살펴보겠습니다.
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 {}
이제 다음과 같은 일이 발생합니다.
이것이 우리 지침의 핵심입니다. reconnectObserver 메소드는 관찰을 시작하는 메소드입니다! 다음과 같을 것입니다:
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; } }
전체 지침은 다음과 같습니다. 이것은 단지 연습이었으므로 원하는 대로 자유롭게 변경하세요!
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; } } }
위 내용은 Angular LAB: 가시성 지시문을 만들어 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!