@trendster-io/ng-lazy-image
Version:
An Angular directive to efficiently lazy load images using the IntersectionObserver API.
150 lines (146 loc) • 3.76 kB
JavaScript
import { EventEmitter, Directive, ElementRef, Input, Output, HostBinding, NgModule } from '@angular/core';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class LazyImageDirective {
/**
* @param {?} el
*/
constructor(el) {
this.el = el;
this.willLoad = new EventEmitter();
this.decodingAttr = 'async';
}
/**
* @return {?}
*/
get visibilityStyle() {
return this.srcAttr ? 'visible' : 'hidden';
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (changes.src && changes.src.currentValue) {
this.addIO();
}
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this.io) {
this.removeIO();
}
}
/**
* @private
* @return {?}
*/
canLazyLoad() {
return typeof window !== 'undefined' && 'IntersectionObserver' in window;
}
/**
* @private
* @return {?}
*/
load() {
this.srcAttr = this.src;
this.willLoad.emit();
}
/**
* @private
* @return {?}
*/
lazyLoadImage() {
// Remove any previous observer if exists
if (this.io) {
this.removeIO();
}
this.io = new IntersectionObserver((/**
* @param {?} entry
* @return {?}
*/
entry => {
// because there will only ever be one instance
// of the element we are observing
// we can just use entry[0]
if (entry[0].isIntersecting) {
this.load();
this.removeIO();
}
}), {
root: this.root,
rootMargin: this.rootMargin,
threshold: this.threshold
});
this.io.observe(this.el.nativeElement);
}
/**
* @private
* @return {?}
*/
loadImage() {
setTimeout((/**
* @return {?}
*/
() => this.load()), 200);
}
/**
* @private
* @return {?}
*/
addIO() {
// Check if window is defined to handle SSR, as well as check for IntersectionObserever support in the browser
if (this.canLazyLoad()) {
this.lazyLoadImage();
}
else {
// Fallback to setTimeout if IntersectionObserver-based lazy loading is not supported
this.loadImage();
}
}
/**
* @private
* @return {?}
*/
removeIO() {
this.io.disconnect();
this.io = null;
}
}
LazyImageDirective.decorators = [
{ type: Directive, args: [{
selector: 'img[lazy]'
},] }
];
/** @nocollapse */
LazyImageDirective.ctorParameters = () => [
{ type: ElementRef }
];
LazyImageDirective.propDecorators = {
src: [{ type: Input }],
root: [{ type: Input }],
rootMargin: [{ type: Input }],
threshold: [{ type: Input }],
willLoad: [{ type: Output }],
srcAttr: [{ type: HostBinding, args: ['attr.src',] }],
decodingAttr: [{ type: HostBinding, args: ['attr.decoding',] }],
visibilityStyle: [{ type: HostBinding, args: ['style.visibility',] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class LazyImageModule {
}
LazyImageModule.decorators = [
{ type: NgModule, args: [{
declarations: [LazyImageDirective],
exports: [LazyImageDirective]
},] }
];
export { LazyImageDirective, LazyImageModule };
//# sourceMappingURL=trendster-io-ng-lazy-image.js.map