Skip to content

Instantly share code, notes, and snippets.

@artemgurzhii
Last active November 14, 2018 07:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save artemgurzhii/2338b55b5148ac88de5770cfa6f100bb to your computer and use it in GitHub Desktop.
Save artemgurzhii/2338b55b5148ac88de5770cfa6f100bb to your computer and use it in GitHub Desktop.
Intersection Observer API usage example on LazyLoadImages
import { preloadImage } from './utils';
/**
* Observe images that doesn't match selector.
*
* @class
* @classdesc If the image gets within 50px in the Y axis, start the download.
*/
export default class LazyLoadImages {
constructor() {
const images = document.getElementsByClassName('.js-lazy-image');
const config = {
rootMargin: '50px 0px',
threshold: LazyLoadImages.THRESHOLD
};
if(!LazyLoadImages.SUPPORTS_INTERSECTION_OBSERVER) {
this._loadImagesImmediately(images);
return;
}
this._count = images.length;
this._onIntersection = this._onIntersection.bind(this);
this._observer = new IntersectionObserver(this._onIntersection, config);
[...images].forEach(img => {
if(img.classList.contains(LazyLoadImages.HANDLED_CLASS)) {
return;
}
this._observer.observe(img);
});
}
// check browser support
static get SUPPORTS_INTERSECTION_OBSERVER() {
return 'IntersectionObserver' in window;
}
// class with which to select images
static get HANDLED_CLASS() {
return 'js-lazy-image--handled';
}
// what % of visiblity of the target the observer should trigger
static get THRESHOLD() {
return 0.01;
}
// initialize new LazyLoadImages loader
static init() {
if(this._instance) {
this._instance._disconnect();
}
this._count = 0;
this._instance = new LazyLoadImages();
}
// disconnect LazyLoadImages loader
// used if new LazyLoadImages() was called
_disconnect() {
if(!this._observer) {
return;
}
this._observer.disconnect();
}
_onIntersection(entries) {
entries.forEach(entry => {
if(entry.intersectionRatio < 0) {
return;
}
this._count--;
this._observer.unobserve(entry.target);
this._preloadImage(entry.target);
});
if(this._count > 0) {
return;
}
this._observer.disconnect();
}
/**
* Preloading image.
*
* @param {String} img - image to preload.
*/
_preloadImage(img) {
const src = img.dataset.src;
if(!src) {
return;
}
return preloadImage(src).then(() => this._applyImage(img, src));
}
/**
* If IntersectionObserver API is not supported, load all images.
*
* @param {Array} images - images to add on the page.
*/
_loadImagesImmediately(images) {
[...images].forEach(image => this._preloadImage(image));
}
/**
* Adding image on the page.
*
* @param {HTMLElement} _img - image to add on the page.
* @param {String} src - image source path.
*/
_applyImage(_img, src) {
const el = _img.querySelector('.js-lazy-image-content');
if(!el) {
return;
}
// Prevent this from being lazy loaded a second time.
_img.classList.add(LazyLoadImages.HANDLED_CLASS);
el.style.backgroundImage = `url(${src})`;
el.classList.add('fade-in');
}
}
import LazyLoadImages from './helpers/lazy-load-images';
LazyLoadImages.init();
/**
* Create and preload image.
*
* @param {String} src - image source path.
* @return {Promise} - created image element.
*/
export function preloadImage(src) {
return new Promise((resolve, reject) => {
const image = document.createElement('img');
image.src = src;
image.onload = resolve;
image.onerror = reject;
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment