<Suspense>是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化。
使用方式
<Suspense> 将在内存中渲染其默认的插槽内容(#default)。如果在这个过程中遇到任何异步依赖,则会进入挂起状态。在挂起状态期间,展示的是后备内容(#fallback)。当所有遇到的异步依赖都完成后,<Suspense> 会进入完成状态,并将展示出默认插槽的内容。
事件
- pending:事件是在进入挂起状态时触发。
- resolve: 事件是在
default插槽完成获取新内容时触发。 - fallback:事件则是在
fallback插槽的内容显示时触发。
父组件
<!-- 父组件 -->
<template>
<div>
<Suspense>
<template #default>
<AsyncVue />
</template>
<template #fallback>
<Skeleton />
</template>
</Suspense>
</div>
</template>
<script setup lang="ts">
import { defineAsyncComponent } from 'vue';
import Skeleton from '@/components/skeleton.vue'
const AsyncVue = defineAsyncComponent(() => import('@/components/sync.vue'))
</script>
<style scoped></style>
挂起状态:骨架屏站位组件(skeleton)
<!-- skeleton.vue-->
<template>
<div>
<div class="sync">
<div class="sync-content">
<div class="img"></div>
<div class="sync-pop">
<div></div>
<div> </div>
</div>
</div>
<hr>
<div class="content"></div>
<div class="content"></div>
</div>
</div>
</template>
<style lang="less" scoped>
.sync {
// background-color: #d4d9e1;
padding: 30px;
}
.sync-content {
display: flex;
align-items: center;
.img {
width: 100px;
height: 100px;
background-color: #d4d9e1;
border-radius: 50%;
margin-right: 20px;
// object-fit: cover;
}
.sync-pop{
width: 20%;
height: 20px;
background-color: #d4d9e1;
}
}
.content{
width: 100%;
height: 20px;
background-color: #d4d9e1;
margin: 20px 0;
}
</style>
完成状态:异步组件(sync)
<!-- sync -->
<template>
<div>
<div class="sync">
<div class="sync-content">
<div><img :src="data.url"></div>
<div class="sync-pop">
<div>{{ data.name }}</div>
<div> </div>
</div>
</div>
<hr>
<div>{{ data.desc }}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { axios } from '@/server/axios';
interface Data {
data: {
url: string,
name: string,
age: number,
desc: string
}
}
const { data } = await axios.get<Data>('./data.json')
</script>
<style lang="less" scoped>
.sync{
background-color: #d4d9e1;
padding: 30px;
}
.sync-content {
display: flex;
align-items: center;
img {
width: 100px;
height: 100px;
// background-color: grey;
border-radius: 50%;
margin-right: 10px;
object-fit: cover;
}
}
</style>
自己封装的小axios
export const axios = {
get <T>(url: string): Promise<T> {
return new Promise((resolve) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.onreadystatechange = () => {
if(xhr.status === 200 && xhr.readyState === 4) {
setTimeout(() => {
resolve(JSON.parse(xhr.responseText))
}, 2000)
}
}
xhr.send(null)
})
}
}
json数据(放在public/目录下资源不会被打包,可以直接访问)
{
"data": {
"name": "James Harden",
"age": 24,
"url": "https://n.sinaimg.cn/sinakd20230413ac/300/w1166h734/20230413/2596-5999a0afc974e76bdc43c261abf62716.jpg",
"desc": "詹姆斯·哈登(James Harden),1989年8月26日出生于美国加利福尼亚州洛杉矶(Los Angeles, California),美国职业篮球运动员,司职后卫,效力于NBA费城76人队"
}
}
附带知识(以下是附带知识,顺便记录)
defineSyncComponent
import { defineAsyncComponent } from 'vue';
//引入方式1
const Sync = defineAsyncComponent(() => import('@/components/suspense/sync.vue'))
//引入方式2
const Sync = defineAsyncComponent(() => {
loader: () => import('@/components/suspense/sync.vue'),
// 加载异步组件时使用的组件
loadingComponent?: Component,
// 展示加载组件前的延迟时间,默认为 200ms
delay: 200,
// 加载失败后展示的组件
errorComponent: ErrorComponent,
// 如果提供了一个 timeout 时间限制,并超时了
// 也会显示这里配置的报错组件,默认值是:Infinity
timeout: 3000
})
异步组件可以拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。vue会将异步组件分开打包。
安装less 、设置路径别名(alias)
npm install less -S -D
vite.config.js配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: [
{
find: "@",
replacement: resolve(__dirname, 'src')
}
]
},
css: {
preprocessorOptions: {
less: {
math: "always", // 括号内才使用数学计算
globalVars: {
// 全局变量
mainColor: "red",
},
},
},
},
})
tsconfig.json添加配置
"baseUrl": ".",
"paths": {
"@/*": [ "src/*" ],
}
ts路径识别问题
在tsconfig.json添加配置
"forceConsistentCasingInFileNames": false,