UNPKG

maz-ui

Version:

A standalone components library for Vue.Js 3 & Nuxt.Js 3

1 lines 5.58 kB
var EMPTY_PHOTO=`data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7`;var DEFAULT_OPTIONS={baseClass:`m-lazy-img`,loadedClass:`m-lazy-loaded`,loadingClass:`m-lazy-loading`,errorClass:`m-lazy-error`,fallbackClass:`m-lazy-fallback`,observerOnce:!0,loadOnce:!1,observerOptions:{threshold:.1}};var LazyImg=class{observers=[];defaultOptions=DEFAULT_OPTIONS;options;onImgLoadedCallback;onImgErrorCallback;hasImgLoaded=!1;constructor(opts={}){this.options=this.buildOptions(opts),this.onImgLoadedCallback=this.imageIsLoaded.bind(this),this.onImgErrorCallback=this.imageHasError.bind(this)}async loadErrorPhoto(){let{default:photo}=await import(`@maz-ui/icons/svg/no-image.svg?url`);return photo}buildOptions(opts){return{...this.defaultOptions,...opts,observerOptions:{...this.defaultOptions.observerOptions,...opts.observerOptions}}}removeClass(el,className){el.classList.remove(className)}addClass(el,className){el.classList.add(className)}removeAllStateClasses(el){this.removeClass(el,this.options.loadedClass),this.removeClass(el,this.options.loadingClass),this.removeClass(el,this.options.errorClass),this.removeClass(el,this.options.fallbackClass)}setBaseClass(el){this.addClass(el,this.options.baseClass)}imageIsLoading(el){this.addClass(el,this.options.loadingClass),this.options.onLoading?.(el)}imageIsLoaded(el){this.hasImgLoaded=!0,this.removeClass(el,this.options.loadingClass),this.addClass(el,this.options.loadedClass),this.options.onLoaded?.(el)}imageHasError(el){this.removeClass(el,this.options.loadingClass),this.addClass(el,this.options.errorClass),this.options.onError?.(el),this.setDefaultPhoto(el)}getSrc(binding){return typeof binding.value==`object`?binding.value.src:binding.value}getImageUrl(el,binding){return this.getImgElement(el).getAttribute(`data-lazy-src`)||this.getSrc(binding)}async setPictureSourceUrls(el){let sourceElements=el.querySelectorAll(`source`);if(sourceElements.length>0)for await(let source of sourceElements){let srcSet=source.getAttribute(`data-lazy-srcset`);if(srcSet)source.srcset=srcSet;else return this.imageHasError(el)}else this.imageHasError(el)}hasBgImgMode(binding){return binding.arg===`bg-image`}isPictureElement(el){return el instanceof HTMLPictureElement}getImgElement(el){return this.isPictureElement(el)?el.querySelector(`img`):el}async setDefaultPhoto(el){if(this.options.fallbackSrc===!1)return;let fallbackSrc=this.options.fallbackSrc;typeof fallbackSrc==`string`&&this.addClass(el,this.options.fallbackClass);let errorPhoto=fallbackSrc??await this.loadErrorPhoto();let sourceElements=el.querySelectorAll(`source`);if(sourceElements.length>0)for await(let source of sourceElements)source.srcset=errorPhoto;else this.setImgSrc(el,errorPhoto)}addEventListenerToImg(el){let imgElement=this.getImgElement(el);imgElement.addEventListener(`load`,()=>this.onImgLoadedCallback(el),{once:!0}),imgElement.addEventListener(`error`,err=>this.onImgErrorCallback(el,err),{once:!0})}async loadImage(el,binding){if(this.imageIsLoading(el),this.isPictureElement(el))this.addEventListenerToImg(el),await this.setPictureSourceUrls(el);else{let imageUrl=this.getImageUrl(el,binding);if(!imageUrl)return this.imageHasError(el);this.hasBgImgMode(binding)?(el.style.backgroundImage=`url('${imageUrl}')`,this.imageIsLoaded(el)):(this.addEventListenerToImg(el),this.setImgSrc(el,imageUrl))}}setImgSrc(el,src){let imgElement=this.getImgElement(el);imgElement.src=src}handleIntersectionObserver(el,binding,entries,observer){this.observers.push(observer);for(let entry of entries)if(entry.isIntersecting){if(this.options.onIntersecting?.(entry.target),this.options.observerOnce&&observer.unobserve(el),this.options.loadOnce&&this.hasImgLoaded)return;this.loadImage(el,binding)}}createObserver(el,binding){let observerCallback=(entries,intersectionObserver)=>{this.handleIntersectionObserver(el,binding,entries,intersectionObserver)};let observerOptions=this.options.observerOptions;new IntersectionObserver(observerCallback,observerOptions).observe(el)}async imageHandler(el,binding,type){if(type===`update`)for await(let observer of this.observers)observer.unobserve(el);globalThis.IntersectionObserver?this.createObserver(el,binding):this.loadImage(el,binding)}async bindUpdateHandler(el,binding,type){await this.imageHandler(el,binding,type)}async add(el,binding){if(this.hasBgImgMode(binding)&&this.isPictureElement(el))throw Error(`[MazLazyImg] You can't use the "bg-image" mode with "<picture />" element`);setTimeout(()=>this.setBaseClass(el),0),el.getAttribute(`src`)||this.setImgSrc(el,EMPTY_PHOTO),await this.bindUpdateHandler(el,binding,`bind`)}async update(el,binding){binding.value!==binding.oldValue&&(this.hasImgLoaded=!1,this.removeAllStateClasses(el),await this.bindUpdateHandler(el,binding,`update`))}remove(el,binding){this.hasImgLoaded=!1,this.hasBgImgMode(binding)&&(el.style.backgroundImage=``),this.removeAllStateClasses(el);for(let observer of this.observers)observer.unobserve(el);this.observers=[]}};var instance;var directive={created(el,binding){instance=new LazyImg(typeof binding.value==`object`?binding.value:{}),instance.add(el,binding)},updated(el,binding){instance.update(el,binding)},unmounted(el,binding){instance.remove(el,binding)}};var plugin={install(app,opts={}){let instance=new LazyImg({...DEFAULT_OPTIONS,...opts,observerOptions:{...DEFAULT_OPTIONS.observerOptions,...opts.observerOptions}});app.directive(`lazy-img`,{created:instance.add.bind(instance),updated:instance.update.bind(instance),unmounted:instance.remove.bind(instance)})}};export{directive as n,plugin as t};