vue3 setup语法糖使用 async/await 时出现页面空白的解决方案

6,963 阅读2分钟

题引:

最近在做一个混合编程的App项目,页面使用vue3来实现的。期间就补充了一些遗落下的知识点,像 setup语法糖 的使用。在实际的开发过程中,由于请求的接口过多,axios就结合async/await来使用,但是在实际效果中,却发现页面会出现空白情况,HTML内容消失了,组件模板没有插入到 HTML,但是当我删除 async 和 await 前缀时,我的 HTML 内容又回来了,因此有了这篇文章。

正文:

在这里简单的提一下 setup 语法糖中有一个特征:setup语法糖中可直接使用 await,不需要写async, setup 会自动变成 async setup。

但是实际开发中,你会发现使用await的时候会出现我上述的问题。研究之后,发现是这种情况导致的,下面放一张官方的讲解图。

image.png

是的,由于我们的每个组件有自己的异步资源加载,它们期间可能出现像挂载时数据还没请求、数据请求出错、以及争夺资源的情况等,那么就会出现上述的空白情况。但是如果使用了 <Suspense> 的话,那么我们就可以在多层级的组件树里面等待各个子组件对应的异步请求依赖,最终在组件树的全部异步处理之后再进行最终的挂载。

因此,为了确保项目中能够在 setup语法糖 中正常使用 async/await ,我们可以使用官方推荐的这个这个模板

<RouterView v-slot="{ Component }">
  <template v-if="Component">
    <Transition mode="out-in">
      <KeepAlive>
        <Suspense>
          <!-- 主要内容 -->
          <component :is="Component"></component>

          <!-- 加载中状态 -->
          <template #fallback>
            正在加载...
          </template>
        </Suspense>
      </KeepAlive>
    </Transition>
  </template>
</RouterView>

但我通过自己创建的demo来测试的时候,发现如果在编辑器保存文件时会出现页面空白的现象(真的测试了好久好emo)。后面才发现是因为keep-alive包裹着suspense出现了冲突(不知其因),要么把suspense去掉,要么把keep-alive放在suspense。最终我选择了这份模板,把keepalive放在suspense里,不仅实现了缓存也可以判断非缓存路由的使用。

<template>
  <RouterView v-slot="{ Component, route }">
    <template v-if="Component">
      <transition :name="route.meta.transition || 'fade'" mode="out-in">
        <Suspense>
          <template #default>
            <KeepAlive v-if="route.meta.keepAlive">
              <component :is="Component" :key="route.path"></component>
            </KeepAlive>
            <component :is="Component" :key="route.path"></component>
          </template>
          <template #fallback>正在加载中...</template>
        </Suspense>
      </transition>
    </template>
  </RouterView>
</template>

当然,我们也可以看到,Suspense 也适用于异步组件,那么我们可以使用 defineAsyncComponent 将我们以往导入的组件变成异步组件,进行更靠谱的异步使用。

<script setup>
import { defineAsyncComponent } from 'vue';
// 正常导入组件的方式
// import Breadcrumb from "@/components/breadcrumb/breadcrumb.vue";

// 异步导入组件,组件成为异步组件
const Breadcrumb = defineAsyncComponent(()=>import("@/components/breadcrumb/breadcrumb.vue"));
</script>
<template>
    <div>
        <Breadcrumb />
    </div>
</template>

补充:

<router-view> 暴露了一个 v-slot API,主要使用 <transition> 和 <keep-alive> 组件来包裹你的路由组件。它会包括两个参数

  • Component: VNodes, 传递给 <component>is prop。
  • route: 解析出的标准化路由地址

收尾:

以上就是解决 setup语法糖 时结合 async/await 中遇到白屏的问题。