共计 3994 个字符,预计需要花费 10 分钟才能阅读完成。
在当今快节奏的数字世界中,网站性能对于吸引用户和取得成功至关重要。然而,对于像首页这样的页面,在不影响性能的前提下优化性能就成了一项挑战。
这就是 Vue 组件懒加载的用武之地。通过将非必要元素的加载推延到可见时进行,开发人员能够加强用户体验,同时确保登陆页面的疾速加载。
懒加载是一种优先加载要害内容,同时推延加载主要元素的技术。这种办法不仅能缩短页面的初始加载工夫,还能节约网络资源,从而使用户界面更轻量、反馈更灵活。
在本文中,我将向你展现一种简略的机制,应用 Intersection Observer API 在 Vue 组件可见时对其进行懒加载。
Intersection Observer API
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 组件可见时对其进行懒加载。如果有一个蕴含许多组件的首页,并心愿改善应用程序的初始加载工夫,这将十分有用。