Vue组件懒加载

Vue,组件 · 浏览次数 : 6

小编点评

**Vue 组件懒加载使用 Intersection Observer API 的步骤:** 1. **定义一个组件**:使用 `defineAsyncComponent` 创建一个异步组件,用于在组件可见时加载内容。 2. **使用 IntersectionObserver API**:在 `onMounted` 方法中创建 IntersectionObserver,观察页面元素的可见性变化。 3. **在元素可见时异步加载组件**:当元素变为可见时,触发 IntersectionObserver 的 `IntersectionObserverEntry` 事件。 4. **处理 IntersectionObserver 事件**:在 `IntersectionObserverEntry` 事件中,使用 `resolveComponent` 将组件异步加载到 `loadingComponent`中。 5. **清理观察器和加载组件**:在 `IntersectionObserverEntry` 事件结束后,清理 IntersectionObserver 和从 DOM 中移除相关的元素。 **示例代码:** ```typescript 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({ loader: () => { return new Promise((resolve) => { // 加载组件的异步过程 resolveComponent = resolve as ComponentResolver; }); }, loadingComponent: defineComponent({ setup() { const elRef = ref(); async function loadComponent() { // 加载组件 const component = await componentLoader(); resolveComponent(component); } onMounted(async () => { // 立即加载组件,如果 IntersectionObserver 不支持 if (!('IntersectionObserver' in window)) { await loadComponent(); return; } const observer = new IntersectionObserver((entries) => { if (!entries[0].isIntersecting) { return; } // 清理观察器并加载组件 observer.disconnect(); loadComponent(); }); // 观察元素变为可见状态 observer.observe(elRef.value); }, }, delay, // 设置默认延迟加载时间 }), errorComponent, // 设置默认错误组件 timeout, }); }; ``` **使用示例:** ```html <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> ```

正文

在当今快节奏的数字世界中,网站性能对于吸引用户和取得成功至关重要。然而,对于像首页这样的页面,在不影响功能的前提下优化性能就成了一项挑战。

这就是 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 创建一个新组件,该组件包含一个渲染函数,用于在传递给 lazyLoadComponentIfVisiblediv 中渲染 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 组件可见时对其进行懒加载。如果有一个包含许多组件的首页,并希望改善应用程序的初始加载时间,这将非常有用。

与Vue组件懒加载相似的内容:

Vue组件懒加载

在当今快节奏的数字世界中,网站性能对于吸引用户和取得成功至关重要。然而,对于像首页这样的页面,在不影响功能的前提下优化性能就成了一项挑战。 这就是 Vue 组件懒加载的用武之地。通过将非必要元素的加载推迟到可见时进行,开发人员可以增强用户体验,同时确保登陆页面的快速加载。 懒加载是一种优先加载关键内

VUE系列之性能优化--懒加载

一、懒加载的基本概念 懒加载是一种按需加载技术,即在用户需要时才加载相应的资源,而不是在页面初始加载时一次性加载所有资源。这样可以减少页面初始加载的资源量,提高页面加载速度和用户体验。 二、Vue 中的懒加载 在 Vue.js 中,懒加载主要用于路由组件的按需加载。Vue Router 提供了非常便

Vue 3深度探索:自定义渲染器与服务端渲染

这篇文章介绍了如何在Vue框架中实现自定义渲染器以增强组件功能,探讨了虚拟DOM的工作原理,以及如何通过SSR和服务端预取数据优化首屏加载速度。同时,讲解了同构应用的开发方式与状态管理技巧,助力构建高性能前端应用。

Vue组件的使用

Vue组件简述 组件化开发是Vue的开发模式,组件是Vue的重要组成部分。 vue私有组件的使用分三步 1.导入:import Left from '@/components/Left.vue' 2.注册:components: { Left } 3.使用:

如何从0开始搭建 Vue 组件库

组件设计是通过对功能及视觉表达中元素的拆解、归纳、重组,并基于可被复用的目的,形成规范化的组件,通过多维度组合来构建整个设计方案,將这些组件整理在一起,便形成组件库。本文我们主要讲述基于Vant CLI的自建组件库。Vant CLI 是一个基于 Vite 实现的 Vue 组件库构建工具,通过 Vant CLI 可以快速搭建一套功能完备的 Vue 组件库。

最近很火的Vue Vine是如何实现一个文件中写多个组件

相信你最近应该看到了不少介绍Vue Vine的文章,这篇文章我们另辟蹊径来讲讲Vue Vine是如何实现在一个文件里面写多个vue组件。

有点儿神奇,原来vue3的setup语法糖中组件无需注册因为这个

前言 众所周知,在vue2的时候使用一个vue组件要么全局注册,要么局部注册。但是在setup语法糖中直接将组件import导入无需注册就可以使用,你知道这是为什么呢?注:本文中使用的vue版本为3.4.19。 关注公众号:【前端欧阳】,给自己一个进阶vue的机会 看个demo 我们先来看个简单的d

使用Ref还是Reactive?

我喜欢Vue 3的Composition API,它提供了两种方法来为Vue组件添加响应式状态:ref和reactive。当你使用ref时到处使用.value是很麻烦的,但当你用reactive创建的响应式对象进行重构时,也很容易丢失响应性。 在这篇文章中,我将阐释你如何来选择reactive以及r

视野修炼-技术周刊第92期 | 薅牛毛

① YakShaving - 薅牛毛 ② CSS OneLiners ③ Vue Vine - 单文件编写多 Vue 组件 ④ CDN 流量被盗刷经历 ⑤ es-toolkit ⑥ console.log 体验优化 ⑦ 诗境 - 根据图片匹配诗句

「AntV」X6 自定义vue节点(vue3)

官方文档 本篇文档只讲解vue3中如何使用,vue2的可以参考下官方文档 安装插件 @antv/x6-vue-shape 添加vue组件 既然使用vue节点,那么我们就需要准备一个vue的组件,这个组件就是节点的一些样式,根据你们的ui自行写代码即可 节点名称