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>