The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. Polyfill can be founded here. PS: Stolen from sample-media-pwa created by @paullewis.
Last active
November 14, 2018 07:56
-
-
Save artemgurzhii/2338b55b5148ac88de5770cfa6f100bb to your computer and use it in GitHub Desktop.
Intersection Observer API usage example on LazyLoadImages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import LazyLoadImages from './helpers/lazy-load-images'; | |
LazyLoadImages.init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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