@trendster-io/ng-lazy-image
Version:
An Angular directive to efficiently lazy load images using the IntersectionObserver API.
159 lines • 9.91 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Directive, ElementRef, EventEmitter, HostBinding, Input, Output } from '@angular/core';
export 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',] }]
};
if (false) {
/**
* @type {?}
* @private
*/
LazyImageDirective.prototype.io;
/** @type {?} */
LazyImageDirective.prototype.src;
/** @type {?} */
LazyImageDirective.prototype.root;
/** @type {?} */
LazyImageDirective.prototype.rootMargin;
/** @type {?} */
LazyImageDirective.prototype.threshold;
/** @type {?} */
LazyImageDirective.prototype.willLoad;
/** @type {?} */
LazyImageDirective.prototype.srcAttr;
/** @type {?} */
LazyImageDirective.prototype.decodingAttr;
/**
* @type {?}
* @private
*/
LazyImageDirective.prototype.el;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF6eS1pbWFnZS5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9AdHJlbmRzdGVyLWlvL25nLWxhenktaW1hZ2UvIiwic291cmNlcyI6WyJsaWIvbGF6eS1pbWFnZS5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixXQUFXLEVBQ1gsS0FBSyxFQUdMLE1BQU0sRUFFUCxNQUFNLGVBQWUsQ0FBQztBQUt2QixNQUFNLE9BQU8sa0JBQWtCOzs7O0lBYTdCLFlBQW9CLEVBQXVCO1FBQXZCLE9BQUUsR0FBRixFQUFFLENBQXFCO1FBUGpDLGFBQVEsR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBRWhCLGlCQUFZLEdBQUcsT0FBTyxDQUFDO0lBS1AsQ0FBQzs7OztJQUovQyxJQUFxQyxlQUFlO1FBQ2xELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUM7SUFDN0MsQ0FBQzs7Ozs7SUFJRCxXQUFXLENBQUMsT0FBc0I7UUFDaEMsSUFBSSxPQUFPLENBQUMsR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFO1lBQzNDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztTQUNkO0lBQ0gsQ0FBQzs7OztJQUVELFdBQVc7UUFDVCxJQUFJLElBQUksQ0FBQyxFQUFFLEVBQUU7WUFDWCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7U0FDakI7SUFDSCxDQUFDOzs7OztJQUVPLFdBQVc7UUFDakIsT0FBTyxPQUFPLE1BQU0sS0FBSyxXQUFXLElBQUksc0JBQXNCLElBQUksTUFBTSxDQUFDO0lBQzNFLENBQUM7Ozs7O0lBRU8sSUFBSTtRQUNWLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztRQUN4QixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3ZCLENBQUM7Ozs7O0lBRU8sYUFBYTtRQUNuQix5Q0FBeUM7UUFDekMsSUFBSSxJQUFJLENBQUMsRUFBRSxFQUFFO1lBQ1gsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1NBQ2pCO1FBQ0QsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLG9CQUFvQjs7OztRQUNoQyxLQUFLLENBQUMsRUFBRTtZQUNOLCtDQUErQztZQUMvQyxrQ0FBa0M7WUFDbEMsMkJBQTJCO1lBQzNCLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLGNBQWMsRUFBRTtnQkFDM0IsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNaLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQzthQUNqQjtRQUNILENBQUMsR0FDRDtZQUNFLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSTtZQUNmLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVTtZQUMzQixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7U0FDMUIsQ0FDRixDQUFDO1FBQ0YsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN6QyxDQUFDOzs7OztJQUVPLFNBQVM7UUFDZixVQUFVOzs7UUFBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUUsR0FBRyxDQUFDLENBQUM7SUFDckMsQ0FBQzs7Ozs7SUFFTyxLQUFLO1FBQ1gsOEdBQThHO1FBQzlHLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQ3RCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztTQUN0QjthQUFNO1lBQ0wscUZBQXFGO1lBQ3JGLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztTQUNsQjtJQUNILENBQUM7Ozs7O0lBRU8sUUFBUTtRQUNkLElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFDakIsQ0FBQzs7O1lBaEZGLFNBQVMsU0FBQztnQkFDVCxRQUFRLEVBQUUsV0FBVzthQUN0Qjs7OztZQVpDLFVBQVU7OztrQkFlVCxLQUFLO21CQUNMLEtBQUs7eUJBQ0wsS0FBSzt3QkFDTCxLQUFLO3VCQUNMLE1BQU07c0JBQ04sV0FBVyxTQUFDLFVBQVU7MkJBQ3RCLFdBQVcsU0FBQyxlQUFlOzhCQUMzQixXQUFXLFNBQUMsa0JBQWtCOzs7Ozs7O0lBUi9CLGdDQUFpQzs7SUFDakMsaUNBQXFCOztJQUNyQixrQ0FBdUI7O0lBQ3ZCLHdDQUE0Qjs7SUFDNUIsdUNBQXNDOztJQUN0QyxzQ0FBOEM7O0lBQzlDLHFDQUF5Qzs7SUFDekMsMENBQXFEOzs7OztJQUt6QyxnQ0FBK0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBEaXJlY3RpdmUsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSG9zdEJpbmRpbmcsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdpbWdbbGF6eV0nXG59KVxuZXhwb3J0IGNsYXNzIExhenlJbWFnZURpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcbiAgcHJpdmF0ZSBpbzogSW50ZXJzZWN0aW9uT2JzZXJ2ZXI7XG4gIEBJbnB1dCgpIHNyYzogc3RyaW5nO1xuICBASW5wdXQoKSByb290OiBFbGVtZW50O1xuICBASW5wdXQoKSByb290TWFyZ2luOiBzdHJpbmc7XG4gIEBJbnB1dCgpIHRocmVzaG9sZDogbnVtYmVyIHwgbnVtYmVyW107XG4gIEBPdXRwdXQoKSB3aWxsTG9hZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgQEhvc3RCaW5kaW5nKCdhdHRyLnNyYycpIHNyY0F0dHI6IHN0cmluZztcbiAgQEhvc3RCaW5kaW5nKCdhdHRyLmRlY29kaW5nJykgZGVjb2RpbmdBdHRyID0gJ2FzeW5jJztcbiAgQEhvc3RCaW5kaW5nKCdzdHlsZS52aXNpYmlsaXR5JykgZ2V0IHZpc2liaWxpdHlTdHlsZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnNyY0F0dHIgPyAndmlzaWJsZScgOiAnaGlkZGVuJztcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZWw6IEVsZW1lbnRSZWY8RWxlbWVudD4pIHt9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzLnNyYyAmJiBjaGFuZ2VzLnNyYy5jdXJyZW50VmFsdWUpIHtcbiAgICAgIHRoaXMuYWRkSU8oKTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pbykge1xuICAgICAgdGhpcy5yZW1vdmVJTygpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY2FuTGF6eUxvYWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmICdJbnRlcnNlY3Rpb25PYnNlcnZlcicgaW4gd2luZG93O1xuICB9XG5cbiAgcHJpdmF0ZSBsb2FkKCk6IHZvaWQge1xuICAgIHRoaXMuc3JjQXR0ciA9IHRoaXMuc3JjO1xuICAgIHRoaXMud2lsbExvYWQuZW1pdCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBsYXp5TG9hZEltYWdlKCk6IHZvaWQge1xuICAgIC8vIFJlbW92ZSBhbnkgcHJldmlvdXMgb2JzZXJ2ZXIgaWYgZXhpc3RzXG4gICAgaWYgKHRoaXMuaW8pIHtcbiAgICAgIHRoaXMucmVtb3ZlSU8oKTtcbiAgICB9XG4gICAgdGhpcy5pbyA9IG5ldyBJbnRlcnNlY3Rpb25PYnNlcnZlcihcbiAgICAgIGVudHJ5ID0+IHtcbiAgICAgICAgLy8gYmVjYXVzZSB0aGVyZSB3aWxsIG9ubHkgZXZlciBiZSBvbmUgaW5zdGFuY2VcbiAgICAgICAgLy8gb2YgdGhlIGVsZW1lbnQgd2UgYXJlIG9ic2VydmluZ1xuICAgICAgICAvLyB3ZSBjYW4ganVzdCB1c2UgZW50cnlbMF1cbiAgICAgICAgaWYgKGVudHJ5WzBdLmlzSW50ZXJzZWN0aW5nKSB7XG4gICAgICAgICAgdGhpcy5sb2FkKCk7XG4gICAgICAgICAgdGhpcy5yZW1vdmVJTygpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAge1xuICAgICAgICByb290OiB0aGlzLnJvb3QsXG4gICAgICAgIHJvb3RNYXJnaW46IHRoaXMucm9vdE1hcmdpbixcbiAgICAgICAgdGhyZXNob2xkOiB0aGlzLnRocmVzaG9sZFxuICAgICAgfVxuICAgICk7XG4gICAgdGhpcy5pby5vYnNlcnZlKHRoaXMuZWwubmF0aXZlRWxlbWVudCk7XG4gIH1cblxuICBwcml2YXRlIGxvYWRJbWFnZSgpOiB2b2lkIHtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMubG9hZCgpLCAyMDApO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRJTygpOiB2b2lkIHtcbiAgICAvLyBDaGVjayBpZiB3aW5kb3cgaXMgZGVmaW5lZCB0byBoYW5kbGUgU1NSLCBhcyB3ZWxsIGFzIGNoZWNrIGZvciBJbnRlcnNlY3Rpb25PYnNlcmV2ZXIgc3VwcG9ydCBpbiB0aGUgYnJvd3NlclxuICAgIGlmICh0aGlzLmNhbkxhenlMb2FkKCkpIHtcbiAgICAgIHRoaXMubGF6eUxvYWRJbWFnZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBGYWxsYmFjayB0byBzZXRUaW1lb3V0IGlmIEludGVyc2VjdGlvbk9ic2VydmVyLWJhc2VkIGxhenkgbG9hZGluZyBpcyBub3Qgc3VwcG9ydGVkXG4gICAgICB0aGlzLmxvYWRJbWFnZSgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcmVtb3ZlSU8oKTogdm9pZCB7XG4gICAgdGhpcy5pby5kaXNjb25uZWN0KCk7XG4gICAgdGhpcy5pbyA9IG51bGw7XG4gIH1cbn1cbiJdfQ==