社区精选|Vue 组件懒加载
今天小编为大家带来的是社区作者 chuck 的文章,让我们一起来学习 Vue 组件懒加载。
本文系翻译,阅读原文:https://mokkapps.de/blog/lazy-load-vue-component-when-it-becomes-visible
Intersection Observer API
异步组件
Vue 3 提供了 defineAsyncComponent,用于仅在需要时异步加载组件。
它返回一个组件定义的 Promise:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
// ...load component from server
resolve(/* loaded component */)
})
})
还可以处理错误和加载状态:
const AsyncComp = defineAsyncComponent({
// the loader function
loader: () => import('./Foo.vue'),
// A component to use while the async component is loading
loadingComponent: LoadingComponent,
// Delay before showing the loading component. Default: 200ms.
delay: 200,
// A component to use if the load fails
errorComponent: ErrorComponent,
// The error component will be displayed if a timeout is
// provided and exceeded. Default: Infinity.
timeout: 3000
})
当组件可见时,我们将使用该功能异步加载组件。
懒加载组件
现在,让我们结合 Intersection Observer API 和 defineAsyncComponent 函数,在组件可见时异步加载它们:
import {
h,
defineAsyncComponent,
defineComponent,
ref,
onMounted,
AsyncComponentLoader,
Component,
} from 'vue';
type ComponentResolver = (component: Component) => void
export const lazyLoadComponentIfVisible = ({
componentLoader,
loadingComponent,
errorComponent,
delay,
timeout
}: {
componentLoader: AsyncComponentLoader;
loadingComponent: Component;
errorComponent?: Component;
delay?: number;
timeout?: number;
}) => {
let resolveComponent: ComponentResolver;
return defineAsyncComponent({
// the loader function
loader: () => {
return new Promise((resolve) => {
// We assign the resolve function to a variable
// that we can call later inside the loadingComponent
// when the component becomes visible
resolveComponent = resolve as ComponentResolver;
});
},
// A component to use while the async component is loading
loadingComponent: defineComponent({
setup() {
// We create a ref to the root element of
// the loading component
const elRef = ref();
async function loadComponent() {
// `resolveComponent()` receives the
// the result of the dynamic `import()`
// that is returned from `componentLoader()`
const component = await componentLoader()
resolveComponent(component)
}
onMounted(async() => {
// We immediately load the component if
// IntersectionObserver is not supported
if (!('IntersectionObserver' in window)) {
await loadComponent();
return;
}
const observer = new IntersectionObserver((entries) => {
if (!entries[0].isIntersecting) {
return;
}
// We cleanup the observer when the
// component is not visible anymore
observer.unobserve(elRef.value);
await loadComponent();
});
// We observe the root of the
// mounted loading component to detect
// when it becomes visible
observer.observe(elRef.value);
});
return () => {
return h('div', { ref: elRef }, loadingComponent);
};
},
}),
// Delay before showing the loading component. Default: 200ms.
delay,
// A component to use if the load fails
errorComponent,
// The error component will be displayed if a timeout is
// provided and exceeded. Default: Infinity.
timeout,
});
};
让我们分解一下上面的代码:
我们创建一个 lazyLoadComponentIfVisible 函数,该函数接受以下参数:
componentLoader:返回一个解析为组件定义的 Promise 的函数
loadingComponent:异步组件加载时使用的组件。
errorComponent:加载失败时使用的组件。
delay:显示加载组件前的延迟。默认值:200 毫秒。
timeout:如果提供了超时时间,则将显示错误组件。默认值:Infinity。
函数返回 defineAsyncComponent,其中包含在组件可见时异步加载组件的逻辑。
主要逻辑发生在 defineAsyncComponent 内部的 loadingComponent 中:
我们使用 defineComponent 创建一个新组件,该组件包含一个渲染函数,用于在传递给 lazyLoadComponentIfVisible 的 div 中渲染 loadingComponent。该渲染函数包含一个指向加载组件根元素的模板ref。
在 onMounted 中,我们会检查 IntersectionObserver 是否受支持。如果不支持,我们将立即加载组件。否则,我们将创建一个 IntersectionObserver,用于观察已加载组件的根元素,以检测它何时变得可见。当组件变为可见时,我们会清理观察者并加载组件。
现在,你可以使用该函数在组件可见时对其进行懒加载:
<script setup lang="ts">
import Loading from './components/Loading.vue';
import { lazyLoadComponentIfVisible } from './utils';
const LazyLoaded = lazyLoadComponentIfVisible({
componentLoader: () => import('./components/HelloWorld.vue'),
loadingComponent: Loading,
});
</script>
<template>
<LazyLoaded />
</template>
总结
在本文中,我们学习了如何使用 Intersection Observer API 和 defineAsyncComponent 函数在 Vue 组件可见时对其进行懒加载。如果有一个包含许多组件的首页,并希望改善应用程序的初始加载时间,这将非常有用。
点击左下角阅读原文,到 SegmentFault 思否社区 和文章作者展开更多互动和交流,“公众号后台“回复“ 入群 ”即可加入我们的技术交流群,收获更多的技术文章~
往期推荐
社区精选|Vue 3 中依赖注入与组件定义相关的那点事儿
社区精选|浏览器要原生实现 React 的并发更新了?
社区精选|谈谈 H5 移动端适配原理