With Vue3, I'm trying to create a Picture component with lazyload integrated to it.
Everything works fine when I load the page and none of the Picture are in viewport (when I scroll down, the images are loaded successively).
However when the page loads and one of the Picture is already on viewport, it loads every other images that are not yet visible.
Here is Picture component
<template>
<div
class="picture"
v-lazy-load="!!placeholder"
>
<img
data-placeholder
class="picture__placeholder"
:src="/^http/.test(placeholder) ? placeholder : require(`@/assets/images/${placeholder}`)"
v-if="placeholder"
>
<img
data-image
class="picture__image"
:alt="alt"
:data-url="/^http/.test(src) ? src : require(`@/assets/images/${src}`)"
>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { DirectiveElement } from '@/scripts/contracts/interfaces'
export default defineComponent({
name: 'Picture',
directives: {
'lazy-load': {
mounted(el: DirectiveElement, binding) {
const image = el.querySelector('.picture__image') as HTMLImageElement
if (!image) {
console.error('[v-lazy-load] provided component doesn\'t contain element with class \'image\'')
return false
}
if (typeof binding.value !== 'boolean') {
console.error('[v-lazy-load] provided value is not a boolean')
return false
}
if (Object.keys(binding.modifiers).length) console.warn('[v-lazy-load] no modifiers allowed')
function loadImage() {
if (image) {
el.eventFn = () => el.classList.add('picture--loaded')
image.addEventListener('load', el.eventFn)
el.eventError = () => console.error('[v-lazy-load] error eventlistener')
image.addEventListener('error', el.eventError)
image.src = image.dataset.url as string
}
}
function handleIntersect(
entries: IntersectionObserverEntry[],
observer: IntersectionObserver,
) {
entries.forEach((entry) => {
if (entry.isIntersecting) {
loadImage()
observer.unobserve(el)
}
})
}
function createObserver() {
const options = { root: null, threshold: 0 }
const observer = new IntersectionObserver(handleIntersect, options)
observer.observe(el)
}
if (window.IntersectionObserver && binding.value) return createObserver()
return loadImage()
},
unmounted(el: DirectiveElement) {
const image = el.querySelector('.picture__image') as HTMLImageElement
if (image) {
image.removeEventListener('load', el.eventFn as EventListener)
image.removeEventListener('error', el.eventError as EventListener)
}
},
},
},
props: {
alt: { type: String, default: '' },
src: { type: String, required: true },
placeholder: { type: String, default: '' },
},
})
</script>
Here the parent component
<template>
<div class="parent">
<Picture
src="desert.jpg"
style="width: 80%;"
placeholder="placeholder.png"
/>
...
<Picture
src="mountain.jpg"
style="width: 80%;"
placeholder="placeholder.png"
/>
</div>
</template>
Can someone help me with this, please?