【Vue3】15-异步组件

198 阅读1分钟

1. 场景

发送网络请求需要时间,在等待请求的过程中,可以先在网页上显示一个 skeleton (骨架屏),提高用户体验

2. 封装 axios,模拟发送请求

export const axios = {
    get <T>(url: string): Promise<T> {
        return new Promise(resolve => {
            // 创建 xhr 对象
            const xhr = new XMLHttpRequest()
            // 创建连接
            xhr.open("GET", url)
            // 监听状态
            xhr.onreadystatechange = () => {
                if(xhr.readystate === 4 && xhr.status === 200) {
                    // 设置定时器,模拟请求需要的时间
                    setTimeout(() => {
                        resolve(JSON.parse(xhr.responseText))
                    }, 2000)
                }
            }
            // 发送请求
            xhr.open(null)
        })
    }
}

3. Suspence 的使用

Suspence 是 vue的 一个内置组件,用来在组件树中协调对异步依赖的处理。
它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。

在初始渲染时,<Suspense> 将在内存中渲染其默认的插槽(#default)内容。如果在这个过程中遇到任何异步依赖,则会进入挂起状态。在挂起状态期间,展示的是后备(#fallback)内容。当所有遇到的异步依赖都完成后<Suspense> 会进入完成状态,并将展示出默认插槽的内容。

父组件中

<template>
    <!-- Suspence 里面放两个插槽,一个是 #default 默认插槽,一个是 #fallback 后备插槽。
        两个插槽都只允许一个直接子节点。-->
    <Suspense>
        <template #default>
            <!-- 异步组件 -->
            <Show></Show>
        </template>
        <template #fallback>
            <!-- skeleton,具体实现就不写了 -->
            <Skeleton></Skeleton>
        </template>
    </Suspense>
</template>

<script setup lang="ts">
import { defineAsyncComponent } from 'vue';
import Skeleton from './components/Skeleton.vue'
// 以下是加载 异步组件
const Show = defineAsyncComponent(() => import('./components/Show.vue'))
</script>

异步组件中

<template>
    加载完成
    {{ data.name  }} -- {{ data.age }}
</template>

<script setup lang="ts">
import { axios } from '../utils/axios'

interface Data {
    data: {
        name: string,
        age: number
    }
}

// 顶层 `await` 表达式会自动让该组件成为一个异步依赖
const { data } = await axios.get<Data>('../../public/data.json')  // 解构出 data
console.log(axios.get<Data>("../../public/data.json").then(res => console.log(res.data)))
</script>

/public/data.json —— 请求的数据地址

{
    "data": {
        "name": "lzy",
        "age": 18
    }
}