社区精选|Vue 组件懒加载

SegmentFault

共 8013字,需浏览 17分钟

 ·

2023-09-26 22:40

今天小编为大家带来的是社区作者 chuck 的文章,让我们一起来学习 Vue 组件懒加载。


本文系翻译,阅读原文:https://mokkapps.de/blog/lazy-load-vue-component-when-it-becomes-visible




在当今快节奏的数字世界中,网站性能对于吸引用户和取得成功至关重要。然而,对于像首页这样的页面,在不影响功能的前提下优化性能就成了一项挑战。
这就是 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 组件可见时对其进行懒加载。如果有一个包含许多组件的首页,并希望改善应用程序的初始加载时间,这将非常有用。




点击左下角阅读原文,到 SegmentFault 思否社区 和文章作者展开更多互动和交流,公众号后台回复“ 入群 ”即可加入我们的技术交流群,收获更多的技术文章~


- END -



往期推荐


社区精选|Vue 3 中依赖注入与组件定义相关的那点事儿


社区精选|浏览器要原生实现 React 的并发更新了?


社区精选|谈谈 H5 移动端适配原理



浏览 346
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报