前言

defineAsyncComponent

1
2
import Home from "./components/Home/index.vue"
import Center from "./components/Center/index.vue"
  • 这样子就算你使用了v-show还是v-if,也会加载资源,不相信可以看控制台~

  • 所以可以通过defineAsyncComponent进行优化

  • 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const AsyncFooWithOptions = defineAsyncComponent({
loader: () => import("./demo.vue"),
//加载过程中的组件
loadingComponent: LoadingComponent,
//加载失败的组件
errorComponent: ErrorComponent,
// 在显示loadingComponent组件之前, 等待多长时间,在加载组件显示之前有一个默认的 200ms 延迟——这是因为在网络状况较好时,加载完成得很快,加载组件和最终组件之间的替换太快可能产生闪烁,反而影响用户感受。
delay: 200,
//加载组件的超时时间,如果超过这个值,则显示错误组件, 默认Infinity永不超时, 单位ms
timeout: 3000
//定义组件是否可以挂起, 默认true
suspensible:true,
/** 异步组件加载失败的回调函数
* err: 错误信息,
* retry: 函数, 调用retry尝试重新加载
* fail: 函数, 指示加载程序结束退出
* attempts: 记录尝试的次数
*/
onError: function(err, retry, fail, attempts) {
}
})

  • 对应ts
1
2
3
4
5
6
7
8
9
export interface AsyncComponentOptions<T = any> {
loader: AsyncComponentLoader<T>;
loadingComponent?: Component;
errorComponent?: Component;
delay?: number;
timeout?: number;
suspensible?: boolean;
onError?: (error: Error, retry: () => void, fail: () => void, attempts: number) => any;
}
  • 当我们使用了defineAsyncComponent的时候,就会发现,我们只有在需要的时候才会被导入
    • 注意,如果用v-show逻辑判断,依旧会被提前导入,v-if才会在需要的时候导入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<style scoped>

</style>
<template>
<button @click="handleHome">切换到首页</button>
<button @click="handleCenter">切换到个人中心页面</button>
<AsyncHome v-if="isShowHome"/>
<AsyncCenter v-if="!isShowHome"/>
</template>
<script setup lang="ts">
import {defineAsyncComponent,ref} from "vue";
import Loading from "./components/Loading/index.vue"

const AsyncHome = defineAsyncComponent({
loader: () => import("./components/Home/index.vue"),
loadingComponent:Loading,
delay:200,
})

const AsyncCenter = defineAsyncComponent({
loader: async () => {
await new Promise(resolve => {
setTimeout(() => {resolve()},2000);
//加载5秒后返回
})
return import("./components/Center/index.vue")
},
loadingComponent:Loading,
delay:200,
})

const isShowHome = ref<boolean>(true);

const handleHome = () => {
isShowHome.value = true;
}

const handleCenter = () => {
isShowHome.value = false;
}
</script>

  • 效果,点击个人中心后,延迟200毫秒后加载AsyncCenter,模拟等待2秒后组件加载完毕

Suspense

  • vue官方文档:https://cn.vuejs.org/guide/built-ins/suspense.html

  • 作用是什么呢?我理解的就是统一异步加载状态

    • 这意味着如果一个组件的父链中有Suspense,它将被视为该Suspense的一个异步依赖。我们的组件的加载、错误、延迟和超时选项将被忽略,而是由Suspense来处理。
  • <Suspense> 组件有两个插槽:#default#fallback。两个插槽都只允许一个直接子节点。在可能的时候都将显示默认槽中的节点。否则将显示后备槽中的节点。

    • 两个插槽都只允许一个直接子节点意思是
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //下面是正确的示例
    <Suspense>
    <template #default>
    <div>
    <button @click="handleHome">切换到首页</button>
    <button @click="handleCenter">切换到个人中心页面</button>
    </div>
    </template>
    </Suspense>
    //下面是错误的示例 vue不会渲染
    <Suspense>
    <button @click="handleHome">切换到首页</button>
    <button @click="handleCenter">切换到个人中心页面</button>
    </Suspense>
  • 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<style scoped>

</style>
<template>
<Suspense>
<template #default>
<div>
<button @click="handleHome">切换到首页</button>
<button @click="handleCenter">切换到个人中心页面</button>
</div>
</template>
<template #fallback>
<Loading/>
</template>
</Suspense>
<AsyncHome v-if="isShowHome"/>
<AsyncCenter v-if="!isShowHome"/>
</template>
<script setup lang="ts">
import {defineAsyncComponent,ref} from "vue";
import Loading from "./components/Loading/index.vue"
import Loading2 from "./components/Loading/index.vue"

const AsyncHome = defineAsyncComponent({
loader: () => import("./components/Home/index.vue"),
loadingComponent:Loading2,
delay:200,
})

const AsyncCenter = defineAsyncComponent({
loader: async () => {
await new Promise(resolve => {
setTimeout(() => {resolve()},2000);
//加载5秒后返回
})
return import("./components/Center/index.vue")
},
loadingComponent:Loading2,
delay:200,
})

const isShowHome = ref<boolean>(true);

const handleHome = () => {
isShowHome.value = true;
}

const handleCenter = () => {
isShowHome.value = false;
}
</script>

  • 说明在,异步组件的Loading提示文本应该是Loading2(加载中),而通过Suspense,自动忽略异步组件Loading状态,采用Suspense当中的加载说明,这一点上面提到过

参考学习文章