...

/

Custom LazyLoad Component

Custom LazyLoad Component

Let’s further improve the lazy load functionality.

We'll cover the following...

We’ve just covered how we can lazy load a component with an Intersection Observer. It’d be admittedly tedious to add the same logic everywhere we want to lazy load components, though, especially if there are a few of them.

Custom component

Let’s create a component that will make it easier to lazy load components when the browser is idle, or if a user scrolls close to the component to render.

Press + to interact
// LazyLoad.vue
<script>
import { ref, watch, onMounted } from 'vue'
import { useIntersectionObserver } from '@/composables'
const isClient = typeof window !== 'undefined'
const loadOnIntersect = ({ containerRef, loadComponent, observerOptions }) => {
const { isIntersecting } = useIntersectionObserver(
containerRef,
observerOptions
)
watch(isIntersecting, isIntersecting => {
isIntersecting && loadComponent()
})
}
const loadOnIdle = ({ loadComponent, idleTimeout }) => {
// Load component immediately if not in the browser environment
// or if one of the necessary APIs is not supported
if(!isClient || Dat!('requestIdleCallback' in window || !('requestAnimationFrame' in window)))
{
loadComponent()
return
}
// Load the component when the browser is free or schedule it
// after the timeout is reached
requestIdleCallback(
() => {
requestAnimationFrame(loadComponent)
},
{ timeout: idleTimeout }
)
}
export default {
props: {
idleTimeout: {
type: Number,
default: 3000,
},
onIdle: {
type: Boolean,
default: false,
},
onVisible: {
type: [Object, Boolean],
default: null,
},
},
setup(props, { slots, emit})
{
const isComponentLoaded = ref(false)
const containerRef = ref(null)
let loadType = 'onIdle'
if(props.onIdle) loadType = 'onIdle'
else if(props.onVisible) loadType = 'onVisible'
const config = {
onIdle: loadOnIdle,
onVisible: loadOnIntersect,
}
const loadComponent = () => {
isComponentLoaded.value = true
emit('loaded')
}
// Call appropriate handler
config[loadType]({
containerRef,
loadComponent,
idleTimeout: props.idleTimeout,
observerOptions: typeof props.onVisible === 'object' ? props.onVisible : {},
})
/**
* If component is to be loaded then pass through slots
* Otherwise, render a div with a ref that is needed for
* the Intersection Observer
*/
return() =>
isComponentLoaded.value ? slots.default() : < div ref = { containerRef }
/>
},
}
</script>

The LazyLoad component accepts the onVisible, onIdle, and idleTimeout props. The onVisible prop ...