社區(qū)精選|Vue 組件懶加載
今天小編為大家?guī)淼氖巧鐓^(qū)作者 chuck 的文章,讓我們一起來學(xué)習(xí) Vue 組件懶加載。
本文系翻譯,閱讀原文:https://mokkapps.de/blog/lazy-load-vue-component-when-it-becomes-visible
Intersection Observer API
異步組件
Vue 3 提供了 defineAsyncComponent,用于僅在需要時(shí)異步加載組件。
它返回一個(gè)組件定義的 Promise:
import { defineAsyncComponent } from 'vue'const AsyncComp = defineAsyncComponent(() => {return new Promise((resolve, reject) => {// ...load component from serverresolve(/* loaded component */)})})
還可以處理錯(cuò)誤和加載狀態(tài):
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})
當(dāng)組件可見時(shí),我們將使用該功能異步加載組件。
懶加載組件
現(xiàn)在,讓我們結(jié)合 Intersection Observer API 和 defineAsyncComponent 函數(shù),在組件可見時(shí)異步加載它們:
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,});};
讓我們分解一下上面的代碼:
我們創(chuàng)建一個(gè) lazyLoadComponentIfVisible 函數(shù),該函數(shù)接受以下參數(shù):
componentLoader:返回一個(gè)解析為組件定義的 Promise 的函數(shù)
loadingComponent:異步組件加載時(shí)使用的組件。
errorComponent:加載失敗時(shí)使用的組件。
delay:顯示加載組件前的延遲。默認(rèn)值:200 毫秒。
timeout:如果提供了超時(shí)時(shí)間,則將顯示錯(cuò)誤組件。默認(rèn)值:Infinity。
函數(shù)返回 defineAsyncComponent,其中包含在組件可見時(shí)異步加載組件的邏輯。
主要邏輯發(fā)生在 defineAsyncComponent 內(nèi)部的 loadingComponent 中:
我們使用 defineComponent 創(chuàng)建一個(gè)新組件,該組件包含一個(gè)渲染函數(shù),用于在傳遞給 lazyLoadComponentIfVisible 的 div 中渲染 loadingComponent。該渲染函數(shù)包含一個(gè)指向加載組件根元素的模板ref。
在 onMounted 中,我們會檢查 IntersectionObserver 是否受支持。如果不支持,我們將立即加載組件。否則,我們將創(chuàng)建一個(gè) IntersectionObserver,用于觀察已加載組件的根元素,以檢測它何時(shí)變得可見。當(dāng)組件變?yōu)榭梢姇r(shí),我們會清理觀察者并加載組件。
現(xiàn)在,你可以使用該函數(shù)在組件可見時(shí)對其進(jìn)行懶加載:
<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>
總結(jié)
在本文中,我們學(xué)習(xí)了如何使用 Intersection Observer API 和 defineAsyncComponent 函數(shù)在 Vue 組件可見時(shí)對其進(jìn)行懶加載。如果有一個(gè)包含許多組件的首頁,并希望改善應(yīng)用程序的初始加載時(shí)間,這將非常有用。
點(diǎn)擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開更多互動和交流,“公眾號后臺“回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~
往期推薦
社區(qū)精選|Vue 3 中依賴注入與組件定義相關(guān)的那點(diǎn)事兒
社區(qū)精選|瀏覽器要原生實(shí)現(xiàn) React 的并發(fā)更新了?
社區(qū)精選|談?wù)?H5 移動端適配原理
