image
image copied to clipboard
Lazy Loading Fails with NuxtImg Custom Slot
Description of the Issue
When the "custom" prop or a placeholder is set, const img = new Image() is immediately triggered to check when the image is ready. This causes immediate loading, preventing lazy loading from working. This behavior is understandable, as NuxtImg in this scenario primarily serves as a provider for optimizations.
The core question is: should we implement lazy loading functionality for this case directly within NuxtImg, or is this a more appropriate scenario for using useImage?
Possible Solution Using useImage
<template>
<span
v-if="!isVisible"
ref="trackerRef"
/>
<slot
v-else-if="!isLoaded"
name="placeholder"
/>
<Transition
appear
v-bind="ThemeTransitions.fade"
>
<img
v-if="isLoaded"
:src="imageUrl"
:srcset="imageSrcset"
:alt="props.alt"
v-bind="$attrs"
>
</Transition>
</template>
<script setup lang="ts">
defineOptions({ inheritAttrs: false })
const trackerRef = ref<HTMLSpanElement | null>(null)
const isLoaded = ref(false)
const isVisible = ref(false)
const props = defineProps<{ src: string, alt?: string, preload?: boolean }>()
const $img = useImage()
const imageUrl = $img(props.src, {})
const imageSrcset = $img.getSizes(props.src, {}).srcset
let observer: IntersectionObserver | null = null
onMounted(() => {
if (trackerRef.value && !isLoaded.value) {
observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
isVisible.value = true
observer?.disconnect()
const img = new window.Image()
img.src = imageUrl
img.onload = () => {
isLoaded.value = true
}
}
})
observer.observe(trackerRef.value)
}
})
onUnmounted(() => {
observer?.disconnect()
})
</script>