vue3异步组件

父组件中,子组件的加载一般是按照先后顺序加载的,子组件加载后才会加载父组件。

一个页面的子组件很多,由于会先加载子组件,那么父组件可能会出现比较长的白屏等待时间

大型项目,可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件Vue 提供defineAsyncComponent方法:

import { defineAsyncComponent } from 'vue';

const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...从服务器获取组件
    resolve(/* 获取到的组件 */);
  });
});

使用import导入组件

得到的 AsyncComp 是一个包裹组件,仅在页面需要它渲染时才调用加载函数。另外,它还会将 props 传给内部的组件,所以你可以使用这个异步的包裹组件无缝地替换原始组件,同时实现延迟加载

import { defineAsyncComponent } from 'vue';

const AsyncComp = defineAsyncComponent(() => import('./components/MyComponent.vue'));

处理加载与错误的状态

异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent() 也支持在高级选项中处理这些状态:

const AsyncComp = defineAsyncComponent({
  // 加载函数 需要返回一个Promise,可以使用动态import的方式,也可以自己new Promise()
  loader: () => import('./Foo.vue'),
  // 加载异步组件时使用的组件,该组件会在异步组件加载时显示,如果异步组件加载很快,可能不会出现loading组件
  loadingComponent: LoadingComponent,
  // 展示加载组件前的延迟时间,默认为 200ms
  delay: 200,
  // 加载失败后展示的组件,可以通过Promise的reject来测试
  errorComponent: ErrorComponent,
  // 如果提供了一个 timeout 时间限制,并超时了
  // 也会显示这里配置的报错组件,默认值是:Infinity
  timeout: 3000
});

如果提供了一个加载组件,它将在内部组件加载时先行显示。在加载组件显示之前有一个默认的 200ms 延迟——这是因为在网络状况较好时,加载完成得太快,导致最终组件的替换可能看起来像是闪烁。

如果提供了一个报错组件,当加载器函数返回的 Promise 被 reject 时,它将被显示出来。你还可以指定一个超时时间,在请求耗时过长时显示报错组件。

动态加载函数方式导入组件

import默认导入的模块是静态的,如果我们将import用于动态导入模块,那么将放回一个 Promise,也就是说我们可以在defineAsyncComponent的加载函数中直接使用import来动态导入一个模块。

若非必要,请不要滥用动态导入

import { defineAsyncComponent } from 'vue';
const VmdContent = defineAsyncComponent(() => {
  return import('@/components/editor/VmdContent.vue');
});
<VmdContent :loading="state.spinning" :result="state.resultData.text"></VmdContent>

示例

new Promise方式

script setup

// app.vue
import { onMounted, defineAsyncComponent } from 'vue';
import Child from './child.vue';
const AsyncChild = defineAsyncComponent(() => new Promise((resolve, reject) => resolve(Child)));
onMounted(() => {
  console.log('app');
});
<template>
  <AsyncChild />
</template>
对象的方式创建

script setup

// app.vue
import {ref, onMounted, defineAsyncComponent } from 'vue'
import LoadingComp from './LoadingComp.vue' //加载中
import ErrorComp from './ErrorComp.vue' //加载错误
const AsyncChild = defineAsyncComponent({
    loader: () => (new Promise((resolve, reject) => reject())),
    loadingComponent: LoadingComp,
    delay: 200,
    errorComponent: ErrorComp,
    timeout: 2000
})
onMounted(() => {
    console.log('app')
})
let isShowAsyncComp = ref(false)
const loader = () => {
  isShowAsyncComp.value = true
}
<template>
    <button @click="loader">加载异步组件</button>
    <AsyncChild v-if="isShowAsyncComp" />
</template>