diff --git a/entry/entry-complete.js b/entry/entry-complete.js index 5ff8ef3a..6fbca4d5 100644 --- a/entry/entry-complete.js +++ b/entry/entry-complete.js @@ -17,6 +17,7 @@ import Transition from '../src/components/transition' // Optional components import Swipe from '../src/components/swipe' import Images from '../src/components/images' +import Lazy from '../src/components/lazy' import Anchors from '../src/components/anchors' import Controls from '../src/components/controls' import Keyboard from '../src/components/keyboard' @@ -45,7 +46,8 @@ const COMPONENTS = { Controls, Keyboard, Autoplay, - Breakpoints + Breakpoints, + Lazy } export default class Glide extends Core { diff --git a/package-lock.json b/package-lock.json index d88ade6d..72a5c933 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,12 @@ { "name": "@glidejs/glide", - "version": "3.5.0", + "version": "3.6.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "3.5.0", + "name": "@glidejs/glide", + "version": "3.6.0", "license": "MIT", "devDependencies": { "@babel/core": "^7.16.0", diff --git a/src/assets/sass/glide.core.scss b/src/assets/sass/glide.core.scss index 87f99d7f..389a66b6 100644 --- a/src/assets/sass/glide.core.scss +++ b/src/assets/sass/glide.core.scss @@ -68,4 +68,24 @@ &#{$sm}rtl { direction: rtl; } + + &__lazy__loaded { + -webkit-animation: fadeInFromNone 0.5s ease-in 0s forwards; + animation: fadeInFromNone 0.5s ease-in 0s forwards; + } } + +@keyframes fadeInFromNone { + 0% { + visibility: hidden; + opacity: 0; + } + 1% { + visibility: visible; + opacity: 0; + } + 100% { + visibility: visible; + opacity: 1; + } +} \ No newline at end of file diff --git a/src/components/lazy.js b/src/components/lazy.js new file mode 100644 index 00000000..0830dc60 --- /dev/null +++ b/src/components/lazy.js @@ -0,0 +1,89 @@ +import { throttle } from '../utils/wait' + +export default function (Glide, Components, Events) { + /** + * Holds reference to settings. + * + * @type {Object} + */ + const settings = Glide.settings + let inView = false + + const Lazy = { + mount () { + /** + * Collection of slide elements + * + * @private + * @type {HTMLCollection} + */ + if (settings.lazy) { + this._wrapper = Components.Html.root + this._slideElements = this._wrapper.querySelectorAll('.glide__slide') + } + }, + + withinView () { + let rect = this._wrapper.getBoundingClientRect() + + if ( + rect.bottom > 0 && + rect.right > 0 && + rect.top <= (window.innerHeight * settings.lazyScrollThreshold || document.documentElement.clientHeight) * settings.lazyScrollThreshold && + rect.left <= (window.innerWidth * settings.lazyScrollThreshold || document.documentElement.clientWidth * settings.lazyScrollThreshold) + ) { + this.lazyLoad() + } + }, + + lazyLoad () { + let length + const additionSlides = settings.lazyInitialSlidesLoaded - 1 + inView = true + if (Glide.index + additionSlides < this._slideElements.length) { + length = Glide.index + additionSlides + } else { + length = Glide.index + } + for (let i = 0; i <= length; i++) { + const img = this._slideElements[i].getElementsByTagName('img')[0] + if (img && img.classList.contains('glide__lazy')) { + if (!this._slideElements[i].classList.contains('glide__lazy__loaded')) { + this.loadImage(img) + } + } + } + }, + + loadImage (image) { + if (image.dataset.src) { + image.src = image.dataset.src + image.classList.add('glide__lazy__loaded') + image.classList.remove('glide__lazy') + image.removeAttribute('data-src') + } + } + } + + Events.on(['mount.after'], () => { + if (settings.lazy) { + Lazy.withinView() + } + }) + + Events.on(['move.after'], throttle(() => { + if (settings.lazy && inView) { + Lazy.lazyLoad() + } else if (settings.lazy) { + Lazy.withinView() + } + }, 100)) + + document.addEventListener('scroll', throttle(() => { + if (settings.lazy && !inView) { + Lazy.withinView() + } + }, 100)) + + return Lazy +} diff --git a/src/defaults.js b/src/defaults.js index 88063601..9b72d837 100644 --- a/src/defaults.js +++ b/src/defaults.js @@ -197,6 +197,29 @@ export default { */ breakpoints: {}, + /** + * Enable lazy loading. + * + * @type {Boolean} + */ + lazy: false, + + /** + * Defines the threshold in which lazy loading will begin. + * For example: a threshold of 1.2 will load the images if the carousel/slider + * is within 120% of the screen width and height + * + * @type {Number} + */ + lazyScrollThreshold: 1.2, + + /** + * Defines the inital amount of slides to be loaded + * + * @type {Number} + */ + lazyInitialSlidesLoaded: 2, + /** * Collection of internally used HTML classes. *