Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | import { Directive, AfterViewInit, OnDestroy } from '@angular/core'; import { Input, Output, EventEmitter, ElementRef} from '@angular/core'; /** * @directive VisibleDirective * @description Detects the visibility of an element in the viewport using the IntersectionObserver API. * Emits an event when the visibility state changes. * * This directive is useful for optimizing performance by triggering events or computations only when the element is visible. * * @example * ```html * <div uppVisible (visibilityChange)="onVisibilityChange($event)"> * Observed Content * </div> * ``` * * ```typescript * onVisibilityChange(isVisible: boolean) { * console.log('Element is visible:', isVisible); * } * ``` */ @Directive({ selector: '[uppVisible]' }) export class VisibleDirective implements AfterViewInit, OnDestroy { private observer: IntersectionObserver | null = null; /** * @input threshold * @description Defines the intersection ratio required to trigger the visibility change. * Defaults to `0.1` (10% of the element must be visible to trigger the event). */ @Input() threshold = 0.1; /** * @output visibilityChange * @description Emits a boolean value indicating whether the element is visible in the viewport. */ @Output() visibilityChange: EventEmitter<boolean> = new EventEmitter(); /** * @constructor * @param elementRef Reference to the DOM element associated with the directive. */ constructor(private elementRef: ElementRef) { // nothing to do } private _isvisible = false; /** * @property isVisible * @description Gets the current visibility state of the element. * @returns {boolean} `true` if the element is visible, otherwise `false`. */ get isVisible(): boolean { return this._isvisible; } /** * @private _UpdateVisibility * @description Updates the visibility state and emits an event if the state changes. * @param {boolean} isCurrentlyVisible - The new visibility state of the element. */ private _UpdateVisibility(isCurrentlyVisible: boolean) { Iif (this._isvisible !== isCurrentlyVisible) { this._isvisible = isCurrentlyVisible; this.visibilityChange.emit(this._isvisible); } } /** * @method ngAfterViewInit * @description Initializes the `IntersectionObserver` and checks the element's initial visibility. * If the element is visible upon initialization, it updates the state accordingly. */ ngAfterViewInit() { this.observer = new IntersectionObserver((entries) => { entries.forEach(entry => { this._UpdateVisibility(entry.isIntersecting); }); }, { threshold: this.threshold }); this.observer.observe(this.elementRef.nativeElement); setTimeout(() => { const _rect = this.elementRef.nativeElement.getBoundingClientRect(); const _visible = _rect.top < window.innerHeight && _rect.bottom > 0; this._UpdateVisibility(_visible); }, 0); } /** * @method ngOnDestroy * @description Cleans up and disconnects the `IntersectionObserver` when the directive is destroyed. * Prevents memory leaks by ensuring the observer is properly disposed of. */ ngOnDestroy() { Iif (this.observer) { this.observer.disconnect(); this.observer = null; } } } |