Можете воспользоваться suspense(vue3) или написать реализацую v-if и + observer,
Пример простой реализации:
Компонент Skeleton
<template>
<div class="lazy-load__component">
<component v-intersection="handleShowComponent" v-if="!isComponentVisible" :is="skeleton" />
<template v-else>
<slot />
</template>
</div>
</template>
<script>
export default {
components: {
allSkeletons: () => import("path/to/skeletons")
},
directives: {
intersection: {
inserted: (el, binding) => {
window.addEventListener("load", () => {
const options = {
rootMargin: "0px",
threshold: 1
};
const callback = entries => {
if (entries[0].isIntersecting) {
binding.value();
observer.unobserve(el);
}
};
const observer = new IntersectionObserver(callback, options);
observer.observe(el);
});
},
}
},
},
props: {
skeleton: {
type: String,
default: 'default-skeleton'
}
},
data() {
return {
isComponentVisible: false,
};
},
computed: {
skeleton() {
return allSkeletons[this.skeleton];
},
},
methods: {
handleShowComponent() {
this.isComponentVisible = true;
},
},
};
</script>
Компонент с использованием Skeleton
<template>
<Skeleton skeleton="someSkeleton">
<div>
Some content
</div>
</Skeleton>
</template>
<script>
export default {
components: {
Skeleton: () => import("path/to/skeleton")
}
};
</script>