vue3内置组件Suspense的使用
Suspense
实验性功能<Suspense> 是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化
<Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
<Suspense> 可以等待的异步依赖有两种:
-
带有异步 setup() 钩子的组件。这也包含了使用 <script setup> 时有顶层 await 表达式的组件。
-
异步组件。
异步组件默认就是“suspensible”的。这意味着如果组件关系链上有一个<Suspense>,那么这个异步组件就会被当作这个<Suspense> 的一个异步依赖。在这种情况下,加载状态是由 <Suspense> 控制,而该组件自己的加载、报错、延时和超时等选项都将被忽略。
异步组件也可以通过在选项中指定 suspensible: false 表明不用 Suspense 控制,并让组件始终自己控制其加载状态
<Suspense> 组件会触发三个事件:pending、resolve 和 fallback。pending 事件是在进入挂起状态时触发。resolve 事件是在 default 插槽完成获取新内容时触发。fallback 事件则是在 fallback 插槽的内容显示时触发。
该组件有两个插槽:
- default:如果default可以显示,那么显示default的内容;
- fallback:如果default无法显示,那么会显示fallback插槽的内容;
<template>{{fullName}}<h1>App Component</h1><Suspense><template #default><AsyncMyComponent /></template><template #fallback>loading....</template><template #error="props"><Error :message="props.error.message" /></template></Suspense>
</template><script setup lang="ts">
import { ref ,computed,defineAsyncComponent} from 'vue'
import Loading from './Loading.vue'
import Error from './Error.vue'const firstName = ref('su')
const lastName = ref('mu')
const fullName = computed(() => firstName.value + lastName.value)
// 定义异步组件
const AsyncMyComponent = defineAsyncComponent({
// 加载函数loader: () => new Promise((resolve, reject) => {setTimeout(() => {resolve(import('./AsyncMyComponent.vue'));}, 3000)}),
// loader: () => import('./AsyncMyComponent.vue'),// 加载超时时间(可选)timeout: 3000,// 加载中的组件(可选)loadingComponent: Loading,// 错误组件(可选)errorComponent: Error,// 延迟显示加载组件的时间(可选)delay: 200,// 加载失败时的错误处理函数(可选)onError: (error: Error, retry: () => void, fail: () => void, attempt: number) => {console.error(`Error loading component: ${error.message}`);if (attempt <= 3) {retry();} else {fail();}}
});
</script><style scoped></style>
AsyncMyComponent.vue
<template><div><h2>Async Home Component</h2><p>{{ message }}</p></div></template><script lang="ts">import { defineComponent, ref, onMounted } from 'vue';export default defineComponent({name: 'AsyncMyComponent',setup() {const message = ref<string | null>(null);onMounted(async () => {try {// 模拟异步请求await new Promise<void>((resolve) => {setTimeout(() => {message.value = '异步数据加载完成';resolve();}, 2000);});} catch (error) {console.error('Error fetching data:', error);throw error;}});return { message };}});</script>
Loading.vue
<template><div class="loading"><p>Loading...</p></div></template><script lang="ts">import { defineComponent } from 'vue';export default defineComponent({name: 'Loading'});</script><style scoped>.loading {display: flex;justify-content: center;align-items: center;height: 100px;font-size: 18px;color: #666;}</style>
Error.vue
<template><div class="error"><p>Error: {{ message }}</p></div></template><script lang="ts">import { defineComponent, PropType } from 'vue';export default defineComponent({name: 'Error',props: {message: {type: String as PropType<string>,required: true}}});</script><style scoped>.error {color: red;background-color: #ffebee;padding: 10px;border-radius: 4px;}</style>