异步组件
当我们的项目达到一定的规模时,对于某些组件来说,我们并不希望一开始全部加载,而是需要的时候进行加载;这样的做得目的可以很好的提高用户体验。
为了实现这个功能,Vue3 中为我们提供了一个方法,即 defineAsyncComponent,这个方法可以传递两种类型的参数,分别是函数类型和对象类型,接下来我们分别学习。
1、知识点
- defineAsyncComponent() 定义异步加载组件
- defineAsyncComponent() options 配置
2、传递工厂函数作为参数
defineAsyncComponent
方法接收一个工厂函数是它的基本用法,这个工厂函数必须返回一个Promise
,Promise
的resolve
应该返回一个组件。
新建views/TestAsync.vue
,页面用两个组件来呈现,代码如下:
<template>
<logo-img />
<hello-world msg="Welcome to Your Vue.js App" />
</template>
<script>
import LogoImg from "../components/LogoImg.vue";
import HelloWorld from "../components/HelloWorld.vue";
export default {
name: "TestAnync",
components: {
LogoImg,
HelloWorld,
},
};
</script>
components 目录新建LogoImg.vue
组件
<template>
<div>
<img src="../assets/logo.png" alt="" />
</div>
</template>
<script>
export default {
name: "LogoImg",
};
</script>
<style scoped lang="scss"></style>
components 目录HelloWorld
组件
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
};
</script>
<style scoped lang="scss"></style>
配置路由和导航,看效果
现在我们将<hello-world>
组件修改为异步组件,修改TestAsync.vue
代码如下:
<template>
<logo-img />
<hello-world msg="Welcome to Your Vue.js App" />
</template>
<script setup>
import { defineAsyncComponent } from "vue";
import LogoImg from "../components/LogoImg.vue";
// 修改为异步组件
const HelloWorld = defineAsyncComponent(() =>
import("../components/HelloWorld.vue")
);
</script>
为了看到效果,将import
延迟执行,完整代码
<template>
<logo-img />
<hello-world msg="Welcome to Your Vue.js App" />
</template>
<script setup>
import { defineAsyncComponent } from "vue";
import LogoImg from "../components/LogoImg.vue";
// 定义一个耗时执行的函数,t 表示延迟的时间,callback 表示需要执行的函数,可选
const time = (t, callback = () => {}) => {
return new Promise((resolve) => {
setTimeout(() => {
callback();
resolve();
}, t);
});
};
// 定义异步组件,这里这样写是为了查看效果
const HelloWorld = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
(async function () {
try {
await time(2000);
const res = await import("../components/HelloWorld.vue");
resolve(res);
} catch (error) {
reject(error);
}
})();
});
});
</script>
运行效果:
当 2s 后才会加载<hello-world>
组件。
3、传递对象类型作为参数
defineAsyncComponent 方法也可以接收一个对象作为参数,该对象中有如下几个参数:
- loader:同工厂函数;
- loadingComponent:加载异步组件时展示的组件;
- errorComponent:加载组件失败时展示的组件;
- delay:显示 loadingComponent 之前的延迟时间,单位毫秒,默认 200 毫秒;
- timeout:如果提供了 timeout,并且加载组件的时间超过了设定值,将显示错误组件,默认值为 Infinity(单位毫秒);
- suspensible:异步组件可以退出
控制,并始终控制自己的加载状态。具体可以参考文档 - onError:一个函数,该函数包含 4 个参数,分别是 error、retry、fail 和 attempts,这 4 个参数分别是错误对象、重新加载的函数、加载程序结束的函数、已经重试的次数。
components 目录新建error.vue
组件
<template>
<div>
<h1>发生错误!</h1>
</div>
</template>
<script>
export default {
name: "error",
};
</script>
<style scoped lang="scss"></style>
views 新建TestAsync1.vue
,使用 defineAsyncComponent`方法的对象类型参数
<template>
<logo-img />
<hello-world msg="Welcome to Your Vue.js App" />
</template>
<script setup>
import { defineAsyncComponent } from "vue";
import LogoImg from "../components/LogoImg.vue";
import ErrorComponent from "../components/error.vue";
// 定义一个耗时执行的函数,t 表示延迟的时间, callback 表示需要执行的函数,可选
const time = (t, callback = () => {}) => {
return new Promise((resolve) => {
setTimeout(() => {
callback();
resolve();
}, t);
});
};
// 记录加载次数
let count = 0;
const HelloWorld = defineAsyncComponent({
// 工厂函数
loader: () => {
return new Promise((resolve, reject) => {
(async function () {
await time(2000);
const res = await import("../components/HelloWorld.vue");
if (++count < 3) {
// 前两次加载手动设置加载失败
reject(res);
} else {
// 大于3次成功
resolve(res);
}
})();
});
},
errorComponent: ErrorComponent,
delay: 0,
timeout: 1000,
suspensible: false,
onError(retry, fail, attempts) {
// 注意,retry/fail 就像 promise 的 resolve/reject 一样:
// 必须调用其中一个才能继续错误处理。
if (attempts < 3) {
// 请求发生错误时重试,最多可尝试 3 次
console.log(attempts);
retry();
} else {
fail();
}
},
});
</script>
加载组件时前两次会请求错误,只有第三次加载才会成功,如果加载失败则会展示ErrorComponent
组件。运行结果如下: