vue3 内置组件 <Suspense>

news2024/11/15 5:49:38

官方文档:
<Suspense>
指南-Suspense

官方提示:
<Suspense> 是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化。

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

异步依赖

要了解 <Suspense> 所解决的问题和它是如何与异步依赖进行交互的,需要了解什么是异步依赖。

<Suspense>主要用于包裹异步组件,这些组件可能需要进行异步数据获取或其他耗时的操作:

<Suspense>
└─ <Dashboard>
   ├─ <Profile>
   │  └─ <FriendStatus>(组件有异步的 setup())
   └─ <Content>
      ├─ <ActivityFeed> (异步组件)
      └─ <Stats>(异步组件)

在这个组件树中有多个嵌套组件,要渲染出它们,首先得解析一些异步资源。

  • 如果没有 <Suspense>组件:
    • 以vue2 项目为例:这个组件树中的全部组件,都需要处理各自的加载、报错和完成状态。在网络不好或数据量过大的时候,可以看到页面上有多个加载状态,它们在不同的时间加载完成,页面显示出内容。
  • 有了 <Suspense> 组件后:
    • 可以在等待整个多层级组件树中的各个异步依赖获取结果时,在顶层展示出加载中或加载失败的状态。

<Suspense> 可以等待的异步依赖有两种:

  1. 带有异步 setup() 钩子的组件。这也包含了使用 <script setup> 时有顶层 await 表达式的组件。

  2. 异步组件。

async setup()

组合式 API 中组件的 setup() 钩子可以是异步的:

export default {
  async setup() {
    const res = await fetch(...)
    const posts = await res.json()
    return {
      posts
    }
  }
}

<script setup>语法糖

<script setup>语法糖中,开发者无法在前面添加async
如果使用 <script setup>,那么顶层 await 表达式会自动让该组件成为一个异步依赖:

<!-- Child.vue -->
<template>
  <div class="child-box">
    <h1>子组件</h1>
    <h2>网易热歌榜</h2>
  </div>
</template>
<script setup lang="ts">
// 获取网易云热歌榜
let res = await fetch('https://api.uomg.com/api/rand.music?sort=热歌榜&format=json')
console.log(res.json()) // 一个Promise
</script>

在父组件中直接引用Child.vue组件:

<template>
  <div class="home-wrap">
    <h1>主页----父组件</h1>
    <Child />
  </div>
</template>
<script setup lang="ts">
import Child from './Child.vue';
</script>

页面没有显示Child.vue的内容,并且在控制台提示:

[Vue warn]: Component : setup function returned a promise, but no boundary was found in the parent component tree. A component with async setup() must be nested in a in order to be rendered.

在这里插入图片描述
setup函数返回了一个promise,但是在父组件树中没有找到<Suspense> 边界。带有async setup()的组件必须嵌套在<Suspense> 中才能呈现。

按照提示修改父组件:

<template>
  <div class="home-wrap">
    <h1>主页----父组件</h1>
    <Suspense>
      <!-- 异步任务ok后 -->
      <template v-slot:default>
        <Child />
      </template>
      <!-- 异步任务未做完时 -->
      <template v-slot:fallback>
        <div>请求中...</div>
      </template>
    </Suspense>
  </div>
</template>
<script setup lang="ts">
import { Suspense } from 'vue';
import Child from './Child.vue';
</script>

页面成功展示Child.vue的内容:
在这里插入图片描述

异步组件

异步组件默认就是suspensible: true的。这意味着如果组件关系链上有一个 <Suspense>,那么这个异步组件就会被当作这个 <Suspense> 的一个异步依赖。在这种情况下,加载状态是由 <Suspense> 控制,而该组件自己的加载、报错、延时和超时等选项都将被忽略。

异步组件也可以通过在选项中指定 suspensible: false 表明不用 Suspense 控制,并让组件始终自己控制其加载状态。

<Suspense>

props

interface SuspenseProps {
  timeout?: string | number
  suspensible?: boolean
}

参数说明:

  • timeout:可选参数。
    • 类型:string | number
    • 作用:指定一个超时时间。如果异步依赖在这个时间内没有解析完成,<Suspense>将不再等待并显示 fallback 内容。
  • suspensible:可选参数。
    • 类型:boolean,默认值为 false
    • 作用:当设置为 true 时,组件树中所有的异步依赖将由父级 Suspense 处理。这对于构建复杂的异步加载场景非常有用,可以将多个异步依赖的处理集中在一个更高层次的 <Suspense> 组件中。

插槽

<Suspense> 组件接受两个插槽:#default#fallback。两个插槽都只允许一个直接子节点。

  • #default 插槽用于放置异步依赖的组件或内容。
    • 如果在渲染时遇到异步组件或具有 async setup() 的组件,<Suspense> 会等待所有异步依赖项解析完成后再显示 #default 插槽的内容。
  • #fallback:在异步依赖解析完成之前,<Suspense> 会显示 #fallback 插槽中的内容。
<Suspense>
  <!-- 具有深层异步依赖的组件 -->
  <template #fallback>
    <Dashboard />
  </template>
  

  <!-- 在 #fallback 插槽中显示 “正在加载中” -->
  <template #fallback>
    Loading...
  </template>
</Suspense>
  1. 初始渲染

    • 在初始渲染时,<Suspense>会开始在内存中渲染#default插槽的内容。
    • 如果<Dashboard />组件(或者它的子组件树)中包含异步依赖,比如异步组件加载或者async setup()函数,那么在处理这些异步依赖的过程中,<Suspense>会进入挂起状态。
    • 例如,假设<Dashboard />组件内部,有一个异步请求数据的方法,在数据请求期间,<Suspense>就会进入挂起状态。
  2. 挂起状态

    • 在挂起状态期间,<Suspense>会展示#fallback插槽中的内容,以向用户提供反馈,表明正在进行一些异步操作。
    • 例如,当<Dashboard />中的异步依赖正在处理时,用户会看到Loading...
  3. 完成状态

    • 当所有的异步依赖都完成后,<Suspense>会进入完成状态,并显示#default插槽的内容。
    • 如果在初次渲染时没有遇到异步依赖,<Suspense>会直接进入完成状态,直接展示#default插槽的内容。

状态切换条件

官方说明:进入完成状态后,只有当默认插槽的根节点被替换时,<Suspense> 才会回到挂起状态。组件树中新的更深层次的异步依赖不会造成 <Suspense> 回退到挂起状态。

  1. 一旦进入完成状态,只有当 #default 插槽的根节点被替换时,<Suspense>才会回到挂起状态。

    • 例如,如果<Dashboard />组件被完全替换为另一个具有异步依赖的组件,那么<Suspense>会重新进入挂起状态。
    • <Suspense>从完成状态因为 #default 插槽根节点被替换而回退到挂起状态时,后备内容不会立即展示。
      而是在等待新内容和异步依赖完成的过程中,仍然展示之前 #default 插槽的内容。
    • 通过设置 timeout 属性,配置过度行为:
      • 在等待渲染新内容耗时超过 timeout 之后,<Suspense> 将会切换为展示后备内容。
      • 设置 timeout: 0 ,一旦#default插槽的根节点被替换,就会立即显示后备内容。
  2. 如果只是在<Dashboard />组件的子组件树中添加了新的异步依赖,<Suspense>不会回退到挂起状态。

事件

<Suspense> 组件会触发三个事件:pendingresolvefallback

  • @pending 是在进入挂起状态时触发。
    • 当异步依赖开始加载时触发。可以在这个事件处理函数中显示加载指示器等。
  • @resolve 是在 default 插槽完成获取新内容时触发。
    • 当所有异步依赖项解析完成时触发。可以在这个事件处理函数中执行一些与异步依赖成功加载相关的逻辑。
  • @fallback 是在 fallback 插槽的内容显示时触发。
    • 当异步依赖没有在规定时间内(如果设置了 timeout)解析完成或者出现错误时触发。可以在这个事件处理函数中处理错误情况或显示特定的 fallback 内容。

错误处理

<Suspense> 组件自身目前还不提供错误处理,可以使用 errorCaptured 选项或者 onErrorCaptured() 钩子,在使用到 <Suspense> 的父组件中捕获和处理异步错误。

errorCaptured 选项

在 Vue 组件的选项中,可以定义errorCaptured方法。这个方法会在捕获到来自子孙组件(包括异步组件)的错误时被调用。

export default {
  errorCaptured(error, component, info) {
    // 处理错误的逻辑
    console.log('Error captured:', error);
    // 可以根据需要返回 false 来阻止错误继续向上传播
    return false;
  }
}

参数说明:
error参数是捕获到的错误对象,component是抛出错误的组件实例,info是一个包含错误来源信息的字符串。


当在包含<Suspense>的父组件中定义了errorCaptured选项时,如果<Suspense>内部的异步组件或异步操作抛出错误,errorCaptured方法将被调用。

<template>
  <div>
    <Suspense>
      <template v-slot:default>
        <Child />
      </template>

      <template v-slot:fallback>
        <div>Loading...</div>
      </template>
    </Suspense>
  </div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  errorCaptured(error, component, info) {
    console.log('Error in Suspense:', error);
  }
});
</script>
<script setup lang="ts">
import { Suspense } from 'vue';
import Child from './Child.vue';
</script>

onErrorCaptured () 钩子(组合式 API)

在 Vue 3 的组合式 API 中,可以使用onErrorCaptured函数来注册一个错误捕获钩子。

<script setup>
import { onErrorCaptured } from 'vue';
onErrorCaptured((error, component, info) => {
  console.log('Error captured with onErrorCaptured:', error);
});
</script>

当在包含<Suspense>的父组件中使用onErrorCaptured钩子时,如果<Suspense>内部的异步组件或异步操作抛出错误,这个钩子将被调用。

注意
errorCaptured方法或onErrorCaptured钩子中,可以根据需要返回false来阻止错误继续向上传播。如果不返回false或者返回true,错误将继续向上传递给父组件的错误处理机制。

嵌套使用

当有多个类似于下方的异步组件 (常见于嵌套或基于布局的路由) 时:

<Suspense>
  <component :is="DynamicAsyncOuter">
    <component :is="DynamicAsyncInner" />
  </component>
</Suspense>

<Suspense> 创建了一个边界,它将如预期的那样解析树下的所有异步组件。

  • 当更改 DynamicAsyncOuter 时,<Suspense> 会正确地等待它
  • 当更改 DynamicAsyncInner 时,嵌套的 DynamicAsyncInner 会呈现为一个空节点,直到它被解析为止 (而不是之前的节点或回退插槽)。

可以使用嵌套的方法来解决这个问题:

<Suspense>
  <component :is="DynamicAsyncOuter">
    <Suspense suspensible> <!-- 像这样 -->
      <component :is="DynamicAsyncInner" />
    </Suspense>
  </component>
</Suspense>

设置 suspensible 属性后,所有异步依赖项处理都会交给父级 <Suspense> (包括发出的事件),而内部 <Suspense> 仅充当依赖项解析和修补的另一个边界。

如果不设置 suspensible 属性,内部的 <Suspense> 将被父级 <Suspense> 视为同步组件。这意味着它将会有自己的回退插槽,如果两个 Dynamic 组件同时被修改,则当子 <Suspense> 加载其自己的依赖关系树时,可能会出现空节点和多个修补周期。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git删除本地分支报错:error: the branch ‘xxx‘ is not fully merged

git删除本地分支报错&#xff1a;error: the branch xxx is not fully merged error: the branch xxx is not fully merged 直接&#xff1a; git branch -D xxx 就可以。 如果删除远程分支&#xff1a; git push origin --delete origin/xxx git强制删除本地分支 git branc…

如何将Git本地代码推送到Gitee云端仓库

如何将Git本地代码推送到Gitee云端仓库 在使用Git进行版本控制时&#xff0c;将本地代码推送到远程仓库是一个基本且重要的操作。本文将详细介绍如何将你的Git本地代码推送到Gitee&#xff08;码云&#xff09;云端仓库。Gitee是一个国内非常流行的代码托管平台&#xff0c;类…

NX—UI界面生成的文件在VS上的设置

UI界面保存生成的三个文件 打开VS创建项目&#xff0c;删除自动生成的cpp文件&#xff0c;将生成的hpp和cpp文件拷贝到项目的目录下&#xff0c;并且在VS项目中添加现有项目。 修改VS的输出路径&#xff0c;项目右键选择属性&#xff0c;链接器中的常规&#xff0c;文件路径D:…

线性代数 第七讲 二次型_标准型_规范型_坐标变换_合同_正定二次型详细讲解_重难点题型总结

文章目录 1.二次型1.1 二次型、标准型、规范型、正负惯性指数、二次型的秩1.2 坐标变换1.3 合同1.4 正交变换化为标准型 2.二次型的主要定理3.正定二次型与正定矩阵4.重难点题型总结4.1 配方法将二次型化为标准型4.2 正交变换法将二次型化为标准型4.3 规范型确定取值范围问题4.…

《中国制药设备行业市场现状分析与发展前景预测研究报告》

报告导读&#xff1a;本报告从国际制药设备发展、国内制药设备政策环境及发展、研发动态、供需情况、重点生产企业、存在的问题及对策等多方面多角度阐述了制药设备市场的发展&#xff0c;并在此基础上对制药设备的发展前景做出了科学的预测&#xff0c;最后对制药设备投资潜力…

​​操作系统 ---- 进程调度的时机、切换与过程

目录 一、进程调度的时机 1.1 什么时候需要进行进程调度与切换&#xff1f; 1.2 什么情况下不能进行进程调度与切换&#xff1f; 二、进程调度的方式 2.1 非抢占方式(Nonpreemptive Mode) 2.2 抢占方式(Preemptive Mode) 三、总结 一、进程调度的时机 进程调度&am…

FreeRTOS内部机制学习04(任务通知和软件定时器)

文章目录 何为任务通知&#xff1f;任务通知使用例子任务通知的优势以及劣势优势劣势 深入源码看看API函数内部干了什么函数的种类函数都做了啥&#xff1f; 软件定时器软件定时器的作用软件定时器内部到底做了什么实现了“闹钟”功能引入守护任务&#xff0c;守护任务做了啥&a…

SprinBoot+Vue网上购物商城的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

我们怎么把自动化测试落地到一个项目上呢?

现在的软件测试行业已经不是原先的点点点的功能测试&#xff0c;要想在软件测试这一行中扎根稳住&#xff0c;就需要你会的很多&#xff0c;不局限于功能测试&#xff0c;还要会自动化测试、接口测试、性能测试等。 今天就来说一下自动化测试&#xff0c;首先什么是自动化测试…

简单分享-获取.txt文件内数据 文件内数据逗号分隔 分隔符 C语言

简单分享-获取.txt文件内数据 文件内数据逗号分隔 分隔符 C语言 数据存储到文件中&#xff0c;把文件数据读取到数组&#xff0c;方便数据处理。 # include <stdio.h> # include <stdlib.h> # include <string.h>#define DATANUM 307200 //数组个数 int ma…

Linux之MySQL定时备份

#!/bin/bash #author: zking #MySQL定义备份并发送邮件 #定义变量 DATE$(date %F"_"%H:%M:%S) HOST127.0.0.1 DBdb1 USERNAMEroot PASSWORDun1xR00t MAILdonkeevip.qq.com BACKUP_DIR/data/db_backup SQL_FILE${DB}_sql_$DATE.sql#判断备份目录是否存在 if [ ! -d $B…

Visual Studio提示:无法安装CPpython.Exe.x64

如果你需要在Visual Studio中使用python环境&#xff0c;而且你本身已经有一个python环境&#xff0c;则只需要将你自己的python环境配置到Visual Studio中即可&#xff0c;可以无视如题报错&#xff0c;将不会产生实质性的问题或影响。 解决办法&#xff1a; 工具->获取工…

zabbix“专家坐诊”第255期问答

问题一 Q&#xff1a;大家好&#xff0c;问一下&#xff0c;zabbix做聚合图的时候&#xff0c;可以做到两根线在一个图里- 吗&#xff1f;还是说只能&#xff0c;单边计算聚合&#xff0c;然后再最后作图的时候&#xff0c;添加两条线上去 A&#xff1a;两个数据吗 Q&#xff…

安全政策与安全意识(上)

目录 1、信息安全保障 信息安全保障的三大支柱 2、网络犯罪 2.1 网络犯罪的概念 网络犯罪与计算机犯罪区别 2.2 网络犯罪的特点 2.3 犯罪形式 2.4 网络犯罪的原因(主观) 2.5 网络犯罪的原因(客观) 2.5预防网络犯罪的对策 2.6 计算机信息网络国际联网安全保护管理办法…

C语言知识体系思维导图

为了更清晰地描述C语言知识体系&#xff0c;笔者用一个结构化的思维导图来概括其主要组成部分。见下&#xff1a; 这个思维导图旨在提供一个全面而系统的视角&#xff0c;帮助学习者逐步构建扎实的C语言知识体系。随着学习的深入&#xff0c;可以根据个人兴趣和职业需求&#x…

缓存预热/雪崩/穿透/击穿

1. 缓存预热 预先将MySQL中的数据同步至Redis的过程 2. 缓存雪崩 Redis主机出现故障&#xff0c;或有大量的key同时过期大面积失效导致Redis不可用 Redis中key设置为永不过期&#xff0c;或者过期时间错开Redis缓存集群实现高可用多缓存结合预防雪崩服务降级 3. 缓存穿透 …

51单片机-AT24C02(IIC总线介绍及其时序编写步骤)-第一节(下一节实战)

IIC开始通信&#xff08;6大步&#xff09; 我以前的文章也有对基本常用的通信协议讲解&#xff0c;如SPI UART IIC RS232 RS485 CAN的讲解&#xff0c;可前往主页查询&#xff0c;&#xff08;2024.9.12,晚上20&#xff1a;53&#xff0c;将AT24C02存储芯片&#xff0c;掉电不…

Element UI按钮组件:构建响应式用户界面的秘诀

Element UI按钮组件&#xff1a;构建响应式用户界面的秘诀 一 . 创建按钮二 . 按钮的属性2.1 type 属性2.2 朴素按钮、圆角按钮2.3 size 属性2.4 圆形按钮2.5 加载状态2.6 禁用功能2.7 默认聚焦 三 . 按钮组 在现代网页设计中&#xff0c;按钮不仅是用户交互的核心元素&#xf…

即插即用篇 | YOLOv10 引入组装式Transformer模块AssembleFormer | arXiv 2024

本改进已同步到YOLO-Magic框架! 摘要—早期检测和准确诊断可以预测恶性疾病转化的风险,从而增加有效治疗的可能性。轻微的症状和小范围的感染区域是一种不祥的警告,是疾病早期诊断的重中之重。深度学习算法,如卷积神经网络(CNNs),已被用于分割自然或医学对象,显示出有希…

保姆级离线+windows环境+大模型前端UI安装(二)

看到很多文章采用docker在windows环境安装python或者是linux环境再装webui的&#xff0c;感觉比较麻烦&#xff0c;不够简洁&#xff0c;本文采用nodejs&#xff0c;来作为客户端引擎。 这篇只讲客户端安装&#xff0c;需要安装后端大模型及其运行的可以参考第一篇&#xff1a…