社区精选|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 serverresolve(/* loaded component */)})})
还可以处理错误和加载状态:
const AsyncComp = defineAsyncComponent({// the loader functionloader: () => import('./Foo.vue'),// A component to use while the async component is loadingloadingComponent: LoadingComponent,// Delay before showing the loading component. Default: 200ms.delay: 200,// A component to use if the load failserrorComponent: 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) => voidexport const lazyLoadComponentIfVisible = ({componentLoader,loadingComponent,errorComponent,delay,timeout}: {componentLoader: AsyncComponentLoader;loadingComponent: Component;errorComponent?: Component;delay?: number;timeout?: number;}) => {let resolveComponent: ComponentResolver;return defineAsyncComponent({// the loader functionloader: () => {return new Promise((resolve) => {// We assign the resolve function to a variable// that we can call later inside the loadingComponent// when the component becomes visibleresolveComponent = resolve as ComponentResolver;});},// A component to use while the async component is loadingloadingComponent: defineComponent({setup() {// We create a ref to the root element of// the loading componentconst 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 supportedif (!('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 anymoreobserver.unobserve(elRef.value);await loadComponent();});// We observe the root of the// mounted loading component to detect// when it becomes visibleobserver.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 failserrorComponent,// 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 移动端适配原理
