91 lines
2.5 KiB
TypeScript
91 lines
2.5 KiB
TypeScript
import { Directive, ElementRef, Input, OnInit, Renderer2 } from '@angular/core';
|
|
|
|
@Directive({
|
|
selector: 'img[appLazyLoad]',
|
|
standalone: true
|
|
})
|
|
export class LazyLoadImageDirective implements OnInit {
|
|
@Input() appLazyLoad: string = '';
|
|
@Input() placeholder: string = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300"%3E%3Crect fill="%23f3f4f6" width="400" height="300"/%3E%3C/svg%3E';
|
|
|
|
private observer: IntersectionObserver | null = null;
|
|
|
|
constructor(
|
|
private el: ElementRef<HTMLImageElement>,
|
|
private renderer: Renderer2
|
|
) {}
|
|
|
|
ngOnInit() {
|
|
// Add loading="lazy" attribute for native lazy loading
|
|
this.renderer.setAttribute(this.el.nativeElement, 'loading', 'lazy');
|
|
|
|
// Set placeholder while image loads
|
|
if (this.placeholder) {
|
|
this.renderer.setAttribute(this.el.nativeElement, 'src', this.placeholder);
|
|
}
|
|
|
|
// Add a CSS class for styling during loading
|
|
this.renderer.addClass(this.el.nativeElement, 'lazy-loading');
|
|
|
|
// Use Intersection Observer for enhanced lazy loading
|
|
if ('IntersectionObserver' in window) {
|
|
this.observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
this.loadImage();
|
|
}
|
|
});
|
|
},
|
|
{
|
|
rootMargin: '50px' // Start loading 50px before image enters viewport
|
|
}
|
|
);
|
|
|
|
this.observer.observe(this.el.nativeElement);
|
|
} else {
|
|
// Fallback for browsers without Intersection Observer
|
|
this.loadImage();
|
|
}
|
|
}
|
|
|
|
private loadImage() {
|
|
const img = this.el.nativeElement;
|
|
const src = this.appLazyLoad || img.getAttribute('data-src');
|
|
|
|
if (src) {
|
|
// Create a new image to preload
|
|
const tempImg = new Image();
|
|
|
|
tempImg.onload = () => {
|
|
this.renderer.setAttribute(img, 'src', src);
|
|
this.renderer.removeClass(img, 'lazy-loading');
|
|
this.renderer.addClass(img, 'lazy-loaded');
|
|
|
|
// Disconnect observer after loading
|
|
if (this.observer) {
|
|
this.observer.disconnect();
|
|
}
|
|
};
|
|
|
|
tempImg.onerror = () => {
|
|
console.error('Failed to load image:', src);
|
|
this.renderer.removeClass(img, 'lazy-loading');
|
|
this.renderer.addClass(img, 'lazy-error');
|
|
|
|
if (this.observer) {
|
|
this.observer.disconnect();
|
|
}
|
|
};
|
|
|
|
tempImg.src = src;
|
|
}
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
if (this.observer) {
|
|
this.observer.disconnect();
|
|
}
|
|
}
|
|
}
|