UNPKG

@pi0/framework7

Version:

Full featured mobile HTML framework for building iOS & Android apps

206 lines (188 loc) 5.84 kB
import $ from 'dom7'; import Utils from '../../utils/utils'; const Lazy = { destroy(pageEl) { const $pageEl = $(pageEl).closest('.page'); if (!$pageEl.length) return; if ($pageEl[0].f7DestroyLazy) { $pageEl[0].f7DestroyLazy(); } }, init(pageEl) { const app = this; const $pageEl = $(pageEl).closest('.page').eq(0); // Lazy images const lazyLoadImages = $pageEl.find('.lazy'); if (lazyLoadImages.length === 0 && !$pageEl.hasClass('lazy')) return; // Placeholder const placeholderSrc = app.params.lazy.placeholder; if (placeholderSrc !== false) { lazyLoadImages.each((index, lazyEl) => { if ($(lazyEl).attr('data-src') && !$(lazyEl).attr('src')) $(lazyEl).attr('src', placeholderSrc); }); } // load image const imagesSequence = []; let imageIsLoading = false; function onImageComplete(lazyEl) { if (imagesSequence.indexOf(lazyEl) >= 0) { imagesSequence.splice(imagesSequence.indexOf(lazyEl), 1); } imageIsLoading = false; if (app.params.lazy.sequential && imagesSequence.length > 0) { imageIsLoading = true; app.lazy.loadImage(imagesSequence[0], onImageComplete); } } function lazyHandler() { app.lazy.load($pageEl, (lazyEl) => { if (app.params.lazy.sequential && imageIsLoading) { if (imagesSequence.indexOf(lazyEl) < 0) imagesSequence.push(lazyEl); return; } imageIsLoading = true; app.lazy.loadImage(lazyEl, onImageComplete); }); } function attachEvents() { $pageEl.on('lazy', lazyHandler); $pageEl.on('scroll', lazyHandler, true); $pageEl.find('.tab').on('tab:mounted tab:show', lazyHandler); app.on('resize', lazyHandler); } function detachEvents() { $pageEl.off('lazy', lazyHandler); $pageEl.off('scroll', lazyHandler, true); $pageEl.find('.tab').off('tab:mounted tab:show', lazyHandler); app.off('resize', lazyHandler); } // Store detach function $pageEl[0].f7DestroyLazy = detachEvents; // Attach events attachEvents(); // Run loader on page load/init lazyHandler(); }, isInViewport(lazyEl) { const app = this; const rect = lazyEl.getBoundingClientRect(); const threshold = app.params.lazy.threshold || 0; return ( rect.top >= (0 - threshold) && rect.left >= (0 - threshold) && rect.top <= (app.height + threshold) && rect.left <= (app.width + threshold) ); }, loadImage(imageEl, callback) { const app = this; const $imageEl = $(imageEl); const bg = $imageEl.attr('data-background'); const src = bg || $imageEl.attr('data-src'); if (!src) return; function onLoad() { $imageEl.removeClass('lazy').addClass('lazy-loaded'); if (bg) { $imageEl.css('background-image', `url(${src})`); } else { $imageEl.attr('src', src); } if (callback) callback(imageEl); $imageEl.trigger('lazy:loaded'); app.emit('lazyLoaded', $imageEl[0]); } function onError() { $imageEl.removeClass('lazy').addClass('lazy-loaded'); if (bg) { $imageEl.css('background-image', `url(${app.params.lazy.placeholder || ''})`); } else { $imageEl.attr('src', app.params.lazy.placeholder || ''); } if (callback) callback(imageEl); $imageEl.trigger('lazy:error'); app.emit('lazyError', $imageEl[0]); } const image = new window.Image(); image.onload = onLoad; image.onerror = onError; image.src = src; $imageEl.removeAttr('data-src').removeAttr('data-background'); // Add loaded callback and events $imageEl.trigger('lazy:load'); app.emit('lazyLoad', $imageEl[0]); }, load(pageEl, callback) { const app = this; let $pageEl = $(pageEl); if (!$pageEl.hasClass('page')) $pageEl = $pageEl.parents('.page').eq(0); if ($pageEl.length === 0) { return; } $pageEl.find('.lazy').each((index, lazyEl) => { const $lazyEl = $(lazyEl); if ($lazyEl.parents('.tab:not(.tab-active)').length > 0) { return; } if (app.lazy.isInViewport(lazyEl)) { if (callback) callback(lazyEl); else app.lazy.loadImage(lazyEl); } }); }, }; export default { name: 'lazy', params: { lazy: { placeholder: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEXCwsK592mkAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==', threshold: 0, sequential: true, }, }, create() { const app = this; Utils.extend(app, { lazy: { init: Lazy.init.bind(app), destroy: Lazy.destroy.bind(app), loadImage: Lazy.loadImage.bind(app), load: Lazy.load.bind(app), isInViewport: Lazy.isInViewport.bind(app), }, }); }, on: { pageInit(page) { const app = this; if (page.$el.find('.lazy').length > 0 || page.$el.hasClass('lazy')) { app.lazy.init(page.$el); } }, pageAfterIn(page) { const app = this; if (page.$el.find('.lazy').length > 0 || page.$el.hasClass('lazy')) { app.lazy.init(page.$el); } }, pageBeforeRemove(page) { const app = this; if (page.$el.find('.lazy').length > 0 || page.$el.hasClass('lazy')) { app.lazy.destroy(page.$el); } }, tabMounted(tabEl) { const app = this; const $tabEl = $(tabEl); if ($tabEl.find('.lazy').length > 0 || $tabEl.hasClass('lazy')) { app.lazy.init($tabEl); } }, tabBeforeRemove(tabEl) { const app = this; const $tabEl = $(tabEl); if ($tabEl.find('.lazy').length > 0 || $tabEl.hasClass('lazy')) { app.lazy.destroy($tabEl); } }, }, };