Suspense 是vue3中将异步组件提升到组件树中的异步组件包容器。
这个组件效果和vue3的异步组件API defineAsyncComponent 相似
其目的都是在组件做异步请求的时候,显示一个loading的等待。
为此我做了一个关于 Suspense 的实验。
我这个项目使用了 tailwind.css 作为减少我样式编写的库,安利一下。
首先准备好两个组件
textBlue.vue
<template>
<div class="text-blue-400">文字1</div>
</template>
<script setup>
const sleep = (delay = 2000) =>
new Promise((resp) => setTimeout(() => resp(), delay));
await sleep(2000);
</script>
textGreen.vue
<template>
<div class="text-green-400">
文字2
</div>
</template>
<script setup>
const sleep = (delay = 2000) =>
new Promise((resp) => setTimeout(() => resp(), delay));
await sleep(2000);
</script>
这两个组件中我使用了sleep函数作为异步请求的模拟
以下是我实验的index组件。
<template>
<div class="card">
<p>测试切换组件</p>
<p>{{ componentType }}</p>
<el-radio-group v-model="componentType">
<el-radio
v-for="item in types"
:label="item.label"
:key="item.label"
></el-radio>
</el-radio-group>
<p>Suspense : </p>
<transition mode="out-in" name="el-fade-in-linear">
<Suspense
@pending="pendingEnv"
@resolve="resolveEnv"
@fallback="fallbackEnv"
:timeout="0"
>
<template #default >
<component :is="componentIs" :key="componentIsKey"></component>
</template>
<template #fallback>
<loadingCmd></loadingCmd>
</template>
</Suspense>
</transition>
</div>
</template>
<script setup>
import textBlue from "./textBlue";
import textGreen from "./textGreen";
import loadingCmd from "./loading";
import errorCmd from "./error";
import { ref, defineAsyncComponent, computed } from "vue-demi";
const componentType = ref("textBlue");
const componentIs = computed(
() =>
types.find((a) => a.label == componentType.value).component || errorCmd
);
const componentIsKey = computed(() => componentType.value || "error");
const types = [
{
label: "textBlue",
component: textBlue,
},
{
label: "textGreen",
component: textGreen,
},
];
function pendingEnv() {
console.log("发生变化");
}
function resolveEnv() {
console.log("加载完成");
}
function fallbackEnv() {
console.log("加载 loading");
}
</script>
这是页面的效果。
刚开始看是没啥,但是我组件切换的时候需要异步请求数据,这个时候不希望用户看到没有数据的组件,
给用户一个等待响应的等待页面。
Suspense组件目前有两个插槽,三个事件,一个属性
插槽
一个是 #default
一个是 #fallback
事件
@pending 组件发生变化时
@fallback 组件发生变化后进入fallback插槽
@resolve 组件加载完成后结束fallback插槽的显示进入到业务组件中
default是你放正常的组件时的插槽,fallback是loading状态组件的插槽,
这里有一个很尬的地方,如果不在 Suspense 中使用 timeout这个属性,那么这个loading就只会有一次被显示,
我之前测试了它的事件,结果发现除了第一次进入页面的时候,它会加载loading组件,
在我切换组件的时候,它反而只会触发pending 和 resolve ,fallback 事件并不会触发,并且#fallback 插槽也不会进入。
在我翻阅文档后才发现这点,当时没有仔细看,后面才发现这个感觉好坑啊。。
给你们看看没有加timeout的时候是什么样子
这是进入页面时发生的变化,但是我切换组件的时候
可以看到并没有触发fallback函数,也没有像第一次进入的时候加载loading
那再来看看加上timeout = ‘0’是什么样子
可以看到组件被切换的时候,Suspense触发了fallback并进入了loading插槽。
所以这个组件如果需要反复的加载loading的话,还是得使用timeout属性赋值为0才行。
以上是我对这个组件的实验性测试,如果你有什么好的发现或其他想要交流的话,敬请留言。
(σ゚∀゚)σ..:*☆ 这里是海星吧,我们下次见,拜拜。