19.异步组件
19.1 为什么要有异步组件
首先来看这样一段代码
父组件App.vue
<template>
<div class="app">
<h3>我是App组件</h3>
<Child></Child>
</div>
</template>
<script>
export default {
name: 'App',
};
</script>
<script setup>
import Child from './components/Child.vue';
</script>
子组件Child.vue
<template>
<div class="child">
<h3>我是Child组件</h3>
{
{ sum }}
</div>
</template>
<script>
export default {
name: 'Child',
};
</script>
<script setup>
let sum = $ref(1);
</script>
把网络切换到慢一点的速度,你会发现这两个组件时同时出来的,所以父组件是会要等子组件加载成功的。如果Child
组件一直没加载成功,那么父组件会一直等着他。
所以引出了异步组件,他可以无需让父组件等待子组件。
19.2 基础用法
在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent
方法来实现此功能
defineAsyncComponent
方法接收一个返回 Promise 的加载函数。这个 Promise 的 resolve
回调方法应该在从服务器获得组件定义时调用。你也可以调用 reject(reason)
表明加载失败。
ES 模块动态导入也会返回一个 Promise,所以多数情况下我们会将它和 defineAsyncComponent
搭配使用。类似 Vite 和 Webpack 这样的构建工具也支持此语法(并且会将它们作为打包时的代码分割点),因此我们也可以用它来导入 Vue 单文件组件:
父组件App.vue
<template>
<div class="app">
<h3>我是App组件</h3>
<Child></Child>
</div>
</template>
<script setup>
// import Child from './components/Child.vue';
import { defineAsyncComponent } from 'vue';
const Child = defineAsyncComponent(() => import('./components/Child.vue'));
</script>
这个时候父组件已经能不用等子组件了,但是,这样还有一个问题:
子组件是占用了父组件的空间的,闪一下突然加载出来很不友好,所以引出了内置组件Suspense
。
19.3 加载与错误状态
异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent()
也支持在高级选项中处理这些状态:
const AsyncComp = defineAsyncComponent({
// 加载函数
loader: () => import('./Foo.vue'),
// 加载异步组件时使用的组件
loadingComponent: LoadingComponent,
// 展示加载组件前的延迟时间,默认为 200ms
delay: 200,
// 加载失败后展示的组件
errorComponent: ErrorComponent,
// 如果提供了一个 timeout 时间限制,并超时了
// 也会显示这里配置的报错组件,默认值是:Infinity
timeout: 3000
})
如果提供了一个加载组件,它将在内部组件加载时先行显示。在加载组件显示之前有一个默认的 200ms 延迟——这是因为在网络状况较好时,加载完成得很快,加载组件和最终组件之间的替换太快可能产生闪烁,反而影响用户感受。
如果提供了一个报错组件,则它会在加载器函数返回的 Promise 抛错时被渲染。你还可以指定一个超时时间,在请求耗时超过指定时间时也会渲染报错组件。
19.4 搭配 Suspense 使用(实验性)
异步组件可以搭配内置的 <Suspense>
组件一起使用,若想了解 <Suspense>
和异步组件之间交互,请参阅 `` 章节。
<Suspense>
是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
19.4.1 异步依赖
要了解 <Suspense>
所解决的问题和它是如何与异步依赖进行交互的,我们需要想象这样一种组件层级结构:
<Suspense>
└─ <Dashboard>
├─ <Profile>
│ └─ <FriendStatus>(组件有异步的 setup())
└─ <Content>
├─ <ActivityFeed> (异步组件)
└─ <Stats>(异步组件)
在这个组件树中有多个嵌套组件,要渲染出它们,首先得解析一些异步资源。如果没有 <Suspense>
,则它们每个都需要处理自己的加载、报错和完成状态。在最坏的情况下,我们可能会在页面上看到三个旋转的加载态,在不同的时间显示出内容。
有了 <Suspense>
组件后,我们就可以在等待整个多层级组件树中的各个异步依赖获取结果时,在顶层展示出加载中或加载失败的状态。
<Suspense>
可以等待的异步依赖有两种:
- 带有异步
setup()
钩子的组件。这也包含了使用<script setup>
时有顶层await
表达式的组件。 - 异步组件。