美文网首页前端开发那些事儿
Vue 3新引入的Suspense组件介绍

Vue 3新引入的Suspense组件介绍

作者: microkof | 来源:发表于2021-01-04 16:51 被阅读0次

    前言

    Suspense是Vue 3新增的内置标签,尽管目前官方文档里并没有Suspense的介绍,但不妨碍我们先学习它。

    每当我们希望组件等待数据获取时(通常在异步API调用中),我们都可以使用Vue3 Composition API制作异步组件。

    以下是异步组件有用的一些实例:

    • 在页面加载之前显示加载动画
    • 显示占位符内容
    • 处理延迟加载的图像

    以前,在Vue 2中,我们必须使用条件(例如 v-if 或 v-else)来检查我们的数据是否已加载并显示后备内容。

    但是现在,Suspense随Vue3内置了,因此我们不必担心跟踪何时加载数据并呈现相应的内容。

    父组件

    我们通过范例学习Suspense,首先编写一个父组件。

    1. <template>

    <template>里使用了<Suspense>标签,即便你完全不懂<Suspense>的用法,看了范例也该看明白,default插槽里要放正式内容,fallback插槽里要放降级内容,我放了一行字Loading ...,你也可以放菊花图之类的东西。

    1. <script setup>

    变量名asyncCom必须与模板里的组件名一致。defineAsyncComponent方法用来动态引入组件。

    <template>
      <div>
        子组件内容:
        <Suspense>
          <template #default>
            <async-com />
          </template>
          <template #fallback>Loading ...</template>
        </Suspense>
      </div>
    </template>
    
    <script setup>
    import { defineAsyncComponent } from "vue";
    const asyncCom = defineAsyncComponent(() => import("./asyncCom.vue"));
    </script>
    

    子组件(asyncCom.vue)

    1. <template>没什么可说的。

    2. <script setup>默认就是异步的,相当于async setup(){},所以你可以放心在里面写await。fetchData是我写的模拟ajax请求的Promise。

    <template>
      <div>
        <ul>
          <li v-for="item in jsonData" :key="item.name">
            {{ item.name }} - {{ item.age }}
          </li>
        </ul>
      </div>
    </template>
    
    <script setup>
    import { ref } from "vue";
    function fetchData() {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve([
            {
              name: "张三",
              age: 15,
            },
            {
              name: "李四",
              age: 17,
            },
          ]);
        }, 1500);
      });
    }
    
    ref: jsonData = await fetchData();
    </script>
    
    

    效果

    页面会显示1.5秒的Loading...,然后显示一个列表。

    原理

    Vue从上到下执行子组件的setup里的全部语句,执行完同步语句(包括await语句)之后,父组件就认为子组件加载完成,在这之前,子组件setup状态始终未pending,所以父组件显示降级内容(Loading...),等子组件setup的状态变成resolved或者rejected,父组件就显示默认内容。

    捕获异常

    先说怎么显示异常:我的计划是,如果出现异常,就不再显示Loading...,而是显示“Loading Error. Retry?”,其中Retry做成一个按钮。

    现在ref: jsonData = await fetchData();这句根本没有考虑异常情况,那么怎么捕获异常呢?

    父组件

    我们定义一个布尔值asyncComShow负责刷新组件,同时给<async-com>绑上事件@retry="retry"。retry函数要做的事情就是隐藏组件然后再显示,借此刷新组件。

    <template>
      <div>
        <Suspense v-if="asyncComShow">
          <template #default>
            <async-com @retry="retry" />
          </template>
          <template #fallback> Loading ... </template>
        </Suspense>
      </div>
    </template>
    
    <script setup>
    import { defineAsyncComponent, nextTick } from "vue";
    const asyncCom = defineAsyncComponent(() => import("./asyncCom.vue"));
    ref: asyncComShow = true;
    function retry() {
      asyncComShow = false;
      nextTick(() => {
        asyncComShow = true;
      });
    }
    </script>
    

    子组件

    首先编写错误提示,然后定义变量errorShow来切换提示。

    const instance = getCurrentInstance();用于提供emit方法向父组件发出retry申请。也可以在顶层定义const context = useContext();,然后用context.emit("retry");,我建议用后者,因为标准且轻量级。

    之后,我们用try...catch...来捕获错误。

    最后,await getList()的await是必须要写的,不然setup生命期会在瞬间结束,Loading提示也只会显示一瞬间。

    <template>
      <div>
        <ul v-if="!errorShow">
          <li v-for="item in jsonData" :key="item.name">
            {{ item.name }} - {{ item.age }}
          </li>
        </ul>
        <div v-else>
          Loading Error. <button @click="retry">Retry?</button>
        </div>
      </div>
    </template>
    
    <script setup>
    import { ref, nextTick, getCurrentInstance } from "vue";
    
    const instance = getCurrentInstance();
    ref: jsonData;
    ref: errorShow = false;
    function fetchData() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          reject([
            {
              name: "张三",
              age: 15,
            },
            {
              name: "李四",
              age: 17,
            },
          ]);
        }, 1500);
      });
    }
    
    function retry() {
      instance.emit("retry");
    }
    
    async function getList() {
      errorShow = false;
      try {
        jsonData = await fetchData();
      } catch (e) {
        errorShow = true;
      }
    }
    
    await getList();
    </script>
    

    相关文章

      网友评论

        本文标题:Vue 3新引入的Suspense组件介绍

        本文链接:https://www.haomeiwen.com/subject/lwjobktx.html