Vue.js - 异步组件详解2(实现异步组件、Suspense组件)
前文我演示了 webpack 通过 import 函数对 math.js 模块进行分包处理(点击查看)。如果想对 Vue.js 组件进行分包处理,那么可以使用 Vue.js 提供的 defineAsyncComponent 函数实现异步加载组件,该函数支持两种类型的参数:
- 工厂函数:该工厂函数需要返回一个 Promise 对象。
- 对象类型:对异步函数进行配置。
下面将分别介绍这两种类型的使用方法。
二、实现异步组件
1,使用工厂函数加载异步组件
(1)首先我们创建一个 Home.vue 组件,将作为普通组件使用,代码如下所示:
<template>
<div>
Home组件
</div>
</template>
<style scoped>
div {
border: solid 1px gray;
padding: 10px;
margin: 10px;
}
</style>
(2)接着我们创建一个 About.vue 组件,将作为异步组件使用,打包时会进行分包处理,代码如下所示:
<template>
<div>
About组件
</div>
</template>
<style scoped>
div {
border: solid 1px gray;
padding: 10px;
margin: 10px;
}
</style>
(3)修改 App.vue 根组件,代码如下所示:
- 首先我们使用普通方式导入 Home.vue 组件时,这种方式不会分包。
- 接着,使用 defineAsyncComponent 函数导入 About.vue 组件,该函数会接收一个工厂函数作为参数。 然后,在工厂函数中使用 import 函数导入 About.vue 组件。defineAsyncComponent 函数返回的组件就是异步加载的组件,这种方式会进行分包处理。
<template>
<div class="app">
App组件
<home></home>
<about></about>
</div>
</template>
<script>
//
import { defineAsyncComponent } from 'vue';
// 以普通方式导入Home.vue组件,不会进行分包处理
import Home from './Home.vue';
// 使用defineAsyncComponent函数以异步方式导入About.vue组件,会进行分包处理
const About = defineAsyncComponent(() => import("./About.vue"))
export default {
components: {
Home,
About
}
}
</script>
(4)打包项目,可以看到,About.vue 组件已经被单独分到 708.4257b3d0.js 文件中,而 Home.vue 组件并没有单独分出来。

(5)保存代码,在浏览器中加载异步组件的效果如下图所示:

2,使用对象类型语法加载异步组件
(1)修改 App.vue,使用使用对象类型语法加载异步组件,代码如下:
<template>
<div class="app">
App组件
<home></home>
<about></about>
</div>
</template>
<script>
// 导入defineAsyncComponent
import { defineAsyncComponent } from 'vue';
// 导入Loading组件
import Loading from './Loding.vue';
// 以普通方式导入Home.vue组件,不会进行分包处理
import Home from './Home.vue';
// 异步组件( defineAsyncComponent接收对象类型参数 )
const About = defineAsyncComponent({
// 需要异步加载的组件
loader: () => import("./About.vue"),
// 加载时显示Loading组件
loadingComponent: Loading,
// 加载失败时显示Error组件
// errorComponent,
// 在显示loadingComponent组件之前, 等待多长时间
delay: 2000,
// 超时时间,默认值为Infinity(即永不超时)
timeout: 30000,
// 定义组件是否可挂起,默认为true
suspensible: false, // false 代表异步组件可以退出 Suspense 控制,并始终控制自己的加载状态。
/**
* err: 错误信息,
* retry: 函数, 调用retry尝试重新加载
* fail: 函数, 调用fail尝试失败
* attempts: 记录尝试的次数
*/
onError: function (err, retry, fail, attempts) {
if (err.message.match(/fetch/) && attempts <= 3) {
// 重试3次
retry();
} else {
// 失败
fail();
}
}
})
export default {
components: {
Home,
About
}
}
</script>
(2)上面仅修改了 defineAsyncComponent 函数的使用语法,其他内容保持不变,因此打包后的效果不会受到影响。最后,再来看看 Loading 组件的实现,代码如下所示:
<template>
<div class="loading">
Loading
</div>
</template>
(3)运行测试,可以看到异步组件区域先显示“Loading”,等异步组件加载完后,“Loading”将变为 About.vue 异步组件的内容。
附:Suspense 组件使用
1,基本介绍
(1)在一个组件树中,如果存在多个异步组件,那么每个异步组件都需要处理自己的加载、报错和完成状态。为了统一这些异步组件,Vuejs 提供了一个内置组件 Suspense,用于在组件树中协调对异步依赖的处理。
(2)Suspense 可以让我们在组件树的上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态,防止在最坏情况下看到多个 Loading 加载状态,并在不同的时间内显示内容。
- 如果在异步组件的父组件链中存在一个 Suspense 组件,那么该异步组件将被视为该 Suspense 组件的异步依赖项。在这种情况下,异步组件的加载状态由 Suspense 控制,异步组件自身的加载、错误、延迟和超时选项都会被忽略。
- 如果想要异步组件退出 Suspense 控制,并始终控制自己的加载状态,那么可以在选项中指定 suspensible:false。
(3)Suspense 组件包含两个插槽:
- default:如果 default 插槽可以显示,则会显示 default 插槽的内容。
- fallback:如果 default 插槽无法显示,则会显示 fallback 插槽的内容。
2,使用样例
(1)修改 App.vue 根组件,在 <template> 模板中使用 <suspense> 内置组件控制异步组件的加载过程。当正在加载异步组件时,显示 <loading> 组件;在异步组件加载完成后,显示 <about> 异步组件的内容。
<template>
<div class="app">
App组件
<home></home>
<suspense>
<template #default>
<about></about>
</template>
<template #fallback>
<loading></loading>
</template>
</suspense>
</div>
</template>
<script>
// 导入defineAsyncComponent
import { defineAsyncComponent } from 'vue';
// 导入Loading组件
import Loading from './Loding.vue';
// 以普通方式导入Home.vue组件,不会进行分包处理
import Home from './Home.vue';
// 使用defineAsyncComponent函数以异步方式导入About.vue组件,会进行分包处理
const About = defineAsyncComponent(() => import("./About.vue"))
export default {
components: {
Home,
About,
Loading
}
}
</script>
(3)运行测试,可以看到异步组件区域先显示“Loading”,等异步组件加载完后,“Loading”将变为 About.vue 异步组件的内容。
