Add image lazyloading utils
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { module } from 'modujs';
|
||||
import { lazyLoadImage } from '../utils/image';
|
||||
import LocomotiveScroll from 'locomotive-scroll';
|
||||
|
||||
export default class extends module {
|
||||
@@ -22,16 +23,17 @@ export default class extends module {
|
||||
})
|
||||
}
|
||||
|
||||
toggleLazy(args) {
|
||||
let src = this.getData('lazy', args.obj.el)
|
||||
if (src.length) {
|
||||
if (args.obj.el.tagName === 'IMG') {
|
||||
args.obj.el.src = src
|
||||
} else {
|
||||
args.obj.el.style.backgroundImage = `url('${src}')`
|
||||
}
|
||||
this.setData('lazy', '', args.obj.el)
|
||||
}
|
||||
/**
|
||||
* Lazy load
|
||||
* See '../utils/image'
|
||||
* Recommended to wrap your image in `.c-lazy`. `-lazy-loaded` modifier will be applied on both parent and children
|
||||
*
|
||||
* @param {obj} | Locomotive Scroll object
|
||||
*/
|
||||
lazyLoad(args) {
|
||||
lazyLoadImage(args.obj.target, null, () => {
|
||||
//callback
|
||||
})
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
79
assets/scripts/utils/image.js
Normal file
79
assets/scripts/utils/image.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import { queryClosestParent } from './html';
|
||||
|
||||
const LAZY_LOADED_IMAGES = []
|
||||
|
||||
export function loadImage(url, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const $img = new Image();
|
||||
if (options.crossOrigin) $img.crossOrigin = options.crossOrigin;
|
||||
|
||||
const loadCallback = () => {
|
||||
resolve({
|
||||
element: $img,
|
||||
...getImageMetadata($img),
|
||||
});
|
||||
}
|
||||
|
||||
if($img.decode) {
|
||||
$img.src = url
|
||||
$img.decode().then(loadCallback).catch(e => {
|
||||
reject(e)
|
||||
})
|
||||
} else {
|
||||
$img.onload = loadCallback
|
||||
$img.onerror = (e) => {
|
||||
reject(e);
|
||||
};
|
||||
$img.src = url
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getImageMetadata($img) {
|
||||
return {
|
||||
url: $img.src,
|
||||
width: $img.naturalWidth,
|
||||
height: $img.naturalHeight,
|
||||
ratio: $img.naturalWidth / $img.naturalHeight,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy load images
|
||||
*
|
||||
* @param {node} | $el
|
||||
* @param {string} | url
|
||||
* @param {function} | callback
|
||||
*/
|
||||
export async function lazyLoadImage($el, url, callback = () => {}) {
|
||||
let src = url ? url : $el.dataset.src
|
||||
|
||||
let loadedImage = LAZY_LOADED_IMAGES.find(image => image.url === src)
|
||||
|
||||
if (!loadedImage) {
|
||||
loadedImage = await loadImage(src)
|
||||
if (!loadedImage.url) return;
|
||||
LAZY_LOADED_IMAGES.push(loadedImage)
|
||||
}
|
||||
|
||||
if($el.src === src) {
|
||||
return
|
||||
}
|
||||
|
||||
if ($el.tagName == "IMG") {
|
||||
$el.src = loadedImage.url;
|
||||
} else {
|
||||
$el.style.backgroundImage = `url(${loadedImage.url})`;
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
let lazyParent = queryClosestParent($el, '.c-lazy')
|
||||
if(lazyParent) {
|
||||
lazyParent.classList.add('-lazy-loaded')
|
||||
lazyParent.style.backgroundImage = ''
|
||||
}
|
||||
$el.classList.add('-lazy-loaded')
|
||||
|
||||
callback?.()
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user