Vue3学习记录(六)--- 组合式API之依赖注入和异步组件

一、依赖注入

1、简介

​ 在前面的笔记中,我们学习过父组件向子组件传递数据时,需要借助props来实现。但如果父组件想要向孙子组件传递数据,那就要连续使用两层props逐级向下传递,如果要接收数据的是更深层的后代组件,则需要连续使用多层props进行逐级传递,代码十分繁琐。

​ 依赖注入(provide/inject)就是来解决这一问题的,该特性可以实现父组件向其后代组件跨层级传递数据,只要父组件向其后代组件提供了依赖(provide),无论两者中间相隔多少组件层级,后代组件都可以注入(inject)父组件提供的依赖,从而实现跨组件层级的数据交互。但过多的使用provide/inject 特性,会增加组件之间的耦合性,降低组件的可复用性,因此不可滥用。

2、provide(提供依赖)
局部provide:

​ 父组件要给后代组件传递数据(提供依赖),需要使用procide(name,value)函数,该函数有两个参数:参数name表示的是传递数据的名称(依赖名称),可以是一个字符串或者一个Symbol,后代组件需要通过依赖名称来查找注入数据的值;参数value表示传递数据的值(依赖值),可以是任意类型的数据,可以是一个数据常量,也可以是一个响应式变量ref

​ 如果注入的数据值是一个响应式变量,则后代组件在使用该数据时,依旧具有响应式状态。

​ 一个组件可以多次调用 provide(),使用不同的依赖名称,注入不同的依赖值。

<script setup>
// 导入需要使用的API
import { ref, provide } from 'vue'// 声明一个响应式变量
let count = ref(0);
// 声明一个普通变量
const text = '一个常量'// 使用provide()注入一个响应式变量
provide('count',count);
// 使用provide()注入一个普通js变量
provide('text',text);
</script>
全局provide:

​ 除了在组件中进行依赖注入,还可以在应用层面进行依赖注入,相当于注入了一个全局的依赖,该依赖可以在应用中的所有组件中注入使用。全局依赖注入需要借助main.jscreateApp()创建的应用实例:

// main.js中导入API
import { createApp, ref } from 'vue'
// 其他。。。// 创建应用实例
const app = createApp(App)
// 声明响应式变量
let test = ref('哈哈哈')
// provide() 传递常量
app.provide('all', 123)
// provide() 传递响应式变量
app.provide('test', test)// 其他。。。

​ 想要声明全局变量除了使用依赖注入之外,还可以利用app.config.globalProperties声明全局变量。

3、inject(注入依赖)

​ 上层组件通过provide()提供依赖之后,后代组件需要通过inject(name[,default,boolean])函数来注入依赖,将上层组件传递的数据接收到当前组件中来。该函数只有一个必选参数name,表示要注入依赖的名称,也就是上层组件中provide()name参数:

<script setup>
// 导入需要使用的API
import { inject } from 'vue';// 注入响应式变量依赖
let count = inject('count')
console.log(count);
// 注入普通变量依赖
let text = inject('text')
console.log(text);
// 注入全局普通变量依赖
let all = inject('all')
console.log(all);
// 注入全局响应式依赖
let test = inject('test')
console.log(test);
</script>

控制台输出:

在这里插入图片描述

​ 根据上面控制台的输出结果可以看出,如果上层组件提供的依赖是一个响应式变量ref,则通过inject()注入的依赖将是该ref对象,不会被解包为变量值,这种方式保持了ref在上层组件和后代组件之间的响应式变化。

默认值:

​ 默认情况下,后代组件中inject()注入的依赖必然是上层组件中已经提供的依赖,否则会抛出一个运行时警告。但如果并不要求注入的依赖被提供过,则可以给依赖设置一个默认值。当inject()未能从上层组件获取到依赖值时,就会将默认值作为依赖的值。这也就是inject()函数的第一个可选参数:

// 注入一个未提供的依赖 并设置默认值
let test2 = inject('test2','默认值')
console.log(test2); // 默认值

​ 如果默认值需要调用一个函数或者初始化一个类来设置,为了避免在用不到默认值的情况下造成的性能消耗,可以使用工厂函数来创建默认值,并通过inject()函数的第二个可选参数,表明第二个参数为一个工厂函数:

// 利用工厂函数设置默认值
let test3 = inject('test3',() => new Object(),true)
console.log(test3);
4、响应式变量的依赖注入

​ 我们在上层组件中可以将响应式变量ref作为提供的依赖,后代组件将该依赖注入之后,也就获取到该ref,自然也可以在后代组件中修改该ref的值,但这样会影响到所有注入该依赖的组件,而且逻辑比较混乱。所以针对响应式数据,建议将所有对响应式数据的更新修改操作都集中保持在提供依赖的组件中

​ 即使需要在后代组件中更新修改响应式数据的值,也可以可以通过在提供依赖的组件中声明并提供一个更新数据的方法。

提供依赖的上层组件:

<script setup>
// 导入需要使用的API
import { ref, provide } from 'vue'
// 声明一个响应式变量
let count = ref(0);
// 声明响应式依赖的更新方法
const changeCount = (n) => {count.value=n
}// 使用provide()注入响应式变量
provide('count',count);
// 使用provide()注入响应式变量的更新方法
provide('changeCount',changeCount)
</script>

注入依赖的后代组件:

<script setup>
// 导入需要使用的API
import { inject } from 'vue';// 注入响应式变量依赖
let count = inject('count')
// 注入响应式变量依赖的更新方法
let changeCount = inject('changeCount')
// 其他。。。
// 调用更新方法修改响应式变量的值
changeCount(1);
// 其他。。。
</script>
5、readonly()

​ 如果想要确保上层组件中提供的依赖数据不被注入依赖的后代组件所修改,则需要借助readonly()函数来设置依赖只读。如果设置只读的是响应式变量ref或着复杂数据类型的JS变量,则在后代组件中尝试修改时,上层组件和后代组件中的变量值都不会被修改;如果设置只读的是简单数据类型的JS变量,则在后代组件中尝试修改时,上层组件的变量值不变,下层组件的变量值会变。

​ 因为传递响应式变量和复杂数据类型的JS变量是将本身的引用传递过去了,上层组件和后代组件中引用的同一个ref;而简单数据类型的JS变量,则将在后代组件中新建了一份变量,与上层组件中的变量并非同一个。

提供依赖的上层组件:

<script setup>
// 导入需要使用的API
import { ref, provide, readonly } from 'vue'
// 声明一个响应式变量
let count = ref(0);
// 声明一个普通变量
const text = '一个常量'// 使用provide()注入一个响应式变量
provide('count',readonly(count));
// 使用provide()注入一个普通js变量
provide('text',readonly(text));
</script>

注入依赖的后代组件:

<script setup>
// 导入需要使用的API
import { inject } from 'vue';// 注入响应式变量依赖
let count = inject('count');
console.log(count.value); // 0
count.value++;
console.log(count.value); // 0
// 注入普通变量依赖
let text = inject('text')
console.log(text); // 一个常量
text = '2222'
console.log(text); // 222 但上层组件中依旧是text
</script>
6、依赖名称冲突

​ 如果上层组件中在提供依赖时,多个依赖使用的同一个依赖名称,则最终后代组件在注入依赖时获取的数据,将是最后一个使用该依赖名称的数据,因为后面的数据会将前面的数据覆盖。。

​ 在构建大型项目时,为了避免依赖名称的冲突,可以使用Symbol作为依赖的名称,因为Symbol数据永远不会重复。将所有Symbol存储到一个单独的js文件中,并将Symbol导出,这样方便Symbol在上层组件和后代组件的中使用。

用来存储Symbol的js文件:

// 将Symbol数据导出
export const oneKey = Symbol()

提供依赖的上层组件:

<script setup>import { provide } from 'vue'import { oneKey } from './keys.js'// 向后代组件提供依赖provide(oneKey, '要提供的数据');
</script>

注入依赖的后代组件:

<script setup>import { inject } from 'vue'import { oneKey } from './keys.js'// 向当前组件注入依赖const test = inject(oneKey);
</script>

​ 更多Symbol相关内容请查看:JavaScript 之 Symbol 数据类型。

二、异步组件

1、简介

​ 异步组件是指以异步的方式去加载组件,这些组件不会在页面初始加载时立即加载,而是在需要渲染到DOM上的时候才加载,从而可以提高应用的加载速度和性能。

​ Vue提供了defineAsyncComponent()方法用来实现异步组件的功能。

2、基本用法

defineAsyncComponent()方法的参数是一个返回Promise的加载函数,当从服务器获取组件成功时调用resolve(),加载失败时调用reject()。加载成功之后,该方法的返回值是一个包装过的组件,使用变量接收返回值后,就可以通过变量在组件模板中使用异步加载的组件了。

<script setup>
// 导入要使用的方法
import { defineAsyncComponent } from 'vue'// 调用方法 异步加载组件 并将加载的组件赋值给AsyncComp
const AsyncComp = defineAsyncComponent(() => {return new Promise((resolve, reject) => {// ...从服务器获取组件// 加载成功resolve(/* 获取到的组件 */)// 加载失败reject(/* 加载失败 */)})
})
</script><template><div><!-- 正常使用AsyncComp组件 --><AsyncComp /></div>
</template>
3、ES模块动态导入

​ ES模块动态导入import,其实也会返回一个Promise,所以可以动态导入Vue单文件组件并与defineAsyncComponent()方法搭配使用,实现组件的异步加载。异步加载获取的是一个包装过的组件,它会将接收到的props和插槽、事件监听器等内容传递给内部加载的异步组件。

​ Vite 和 Webpack等构建工具也都支持该语法。

<template><div><div v-if="show"><AsyncChild /></div></div>
</template><script setup>
// 导入需要使用的API
import { ref, defineAsyncComponent } from 'vue'
// 声明响应式变量
let show = ref(false)
// 设置定时器 修改响应式变量的值
setTimeout(() => {show.value = true;
},3000)// 异步加载组件 会在页面渲染 <AsyncChild> 时 调用执行
const AsyncChild = defineAsyncComponent(() => {console.log('加载异步组件');return import('../components/Child3.vue')
})
</script>

与普通组件一样,异步组件也支持通过app.component()注册为全局组件:

// main.js 
app.component('AsyncChild', defineAsyncComponent(() =>import('../components/Child3.vue')
))
4、加载与错误状态

​ 既然是异步加载,那就必然会涉及到加载中和加载失败的状态,defineAsyncComponent() 方法在高级选项中提供了处理这些状态方法,包括加载状态显示、加载错误兜底展示等内容:

const AsyncComp = defineAsyncComponent({// 异步加载组件函数 loader: () => import('../components/Child3.vue'),// 加载中状态 展示的组件loadingComponent: LoadingComponent,// 展示加载组件前的延迟时间,默认为 200ms 避免加载太快导致的闪烁问题delay: 200,// 加载失败状态 展示的组件errorComponent: ErrorComponent,// 可以指定 timeout 时间限制,超时后也会显示这里配置的报错组件,默认值是:Infinity 无限timeout: 3000
})
5、Suspense

​ 异步组件可以搭配内置的 <Suspense> 组件一起使用,但<Suspense> 目前还是一项实验性功能,因此这里就不展开介绍了,感兴趣的小伙伴可以查阅相应文档:Suspense

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库(mysql)-新手笔记-基本知识点(1)

基本概念 数据库 Database :存储数据的容器 表 Table : 在数据库中存储的基本结构,它由行和列组成 行 Row : 表中的一条记录 列 Column : 表中的字段,定义了数据的类型和约束 数据类型 数据值 如 INT(整型),FLAOT(浮点型) ,DECIMAL (精确小数点) 字符串 如 VARCHAR(可变长度字…

基于OpenCV的图形分析辨认03

目录 一、前言 二、实验目的 三、实验内容 四、实验过程 一、前言 编程语言&#xff1a;Python&#xff0c;编程软件&#xff1a;vscode或pycharm&#xff0c;必备的第三方库&#xff1a;OpenCV&#xff0c;numpy&#xff0c;matplotlib&#xff0c;os等等。 关于OpenCV&…

微信小程序云开发教程——墨刀原型工具入门(编辑页面)

引言 作为一个小白&#xff0c;小北要怎么在短时间内快速学会微信小程序原型设计&#xff1f; “时间紧&#xff0c;任务重”&#xff0c;这意味着学习时必须把握微信小程序原型设计中的重点、难点&#xff0c;而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…

Hello C++ (c++是什么/c++怎么学/c++推荐书籍)

引言 其实C基础语法基本上已经学完&#xff0c;早就想开始写C的博客了&#xff0c;却因为其他各种事情一直没开始。原计划是想讲Linux系统虚拟机安装的&#xff0c;后来考虑了一下还是算了&#xff0c;等Linux学到一定程度再开始相关博客的写作和发表吧。今天写博客想给C开个头…

excel 动态列导出

excel动态列&#xff0c;只好用poi来写了&#xff0c;也并不复杂&#xff0c;一样就这个件事情抽像为几步&#xff0c;就是套路了&#xff0c;开发效率就上去了。 1 准备空模板 导出操作与excel模板的导出一样&#xff0c;可以参考excel导出标准化 2 自定义SheetWriteHandler …

Python 一步一步教你用pyglet制作汉诺塔游戏

目录 汉诺塔游戏 1. 抓取颜色 2. 绘制圆盘 3. 九层汉塔 4. 绘制塔架 5. 叠加圆盘 6. 游戏框架 汉诺塔游戏 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;是一个源于印度古老传说的益智玩具。这个传说讲述了大梵天创造世界的时候&#xff0c;他做了三根金刚…

Python错题集-8:AttributeError(找不到对应的对象的属性)

1问题描述 AttributeError: AxesSubplot object has no attribute arc 2代码详情 import matplotlib.pyplot as plt# 创建一个新的图形和坐标轴 fig, ax plt.subplots()# 定义弧线的参数 center (0.5, 0.5) # 圆心坐标 (x, y) width 1.0 # 半径 height 0.5 # 半径 ang…

使用阿里云服务器搭建网站简单吗?超简单教程

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网aliyunfuwuqi.com以搭建WordPress网站博客为例&#xff0c;来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流…

AI领域再出“王炸“----Claude3是否会成为下一个“神“

目录 一.Claude3最新发布 二.Claude3支持20万token 三.Claude3在未公开算法上取得重大突破 1.Claude 3读懂博士论文 2.量子跃迁集成&#xff1a; Claude 3智商&#xff1a;101 测试方法 测试细节 通过Karpathy挑战 Claude 3自画像&#xff0c;突破本我 从洛杉矶排到…

MySQl基础入门⑦

上一章知识内容 分析数据且区分数据类型 看下表分析数据的特征&#xff0c;根据其特征确定相应的数据类型。 分析以上表格特征&#xff0c;确定数据类型&#xff0c;并对数据进行分类。分析数据后按固定长度字符串、可变长度字符串、整数、固定精度小数和日期时间数据类型对数…

VS Code引入ECharts

Charts是一个使用 JavaScript 实现的开源可视化库&#xff0c;涵盖各行业图表&#xff0c;提供了丰富的图表类型和交互能力。&#xff08;摘自菜鸟教程&#xff09; 下面我们来介绍一下VS Code引入ECharts的相关操作 检查电脑是否已经安装了Java语言的软件开发工具包 ECharts…

WebMagic框架

1.webmagic框架 webmagic框架是一个Java实现的爬虫框架&#xff0c;底层依然是HttpClient和jsoup 组件&#xff1a; downloader&#xff1a;下载器组件PageProcessor&#xff1a;页面解析组件&#xff08;必须自定义&#xff09;scheculer&#xff1a;访问队列组件pipeline&am…

kafka查看消息两种方式(命令行和软件)+另附发送消息方式

1、命令行方式 ①找到kafka安装文件夹 ②执行命令 #指定offset为指定时间作为消息起始位置 kafka-consumer-groups.sh \ --bootstrap-server 20.2.246.116:9092 \ --group group_1 \ --topic lanxin_qiao \ --reset-offsets \ --to-datetime 2023-07-19T01:00:00.000 \ -exe…

Linux--基础命令

一.pwd&#xff08;Print Working Directory&#xff09; (1)pwd:显示当前位置的绝对路径; 二.cd (Change Directory) (2)cd:切换目录,cd的参数表示要切换的位置,可以使用绝对路径或者相对路径; 三.ls (3)ls:显示目录中的文件 (l a i) ls补充: 理解使用: -A 显现除 “.”和“…

20-Java备忘录模式 ( Memento Pattern )

Java备忘录模式 摘要实现范例 备忘录模式&#xff08;Memento Pattern&#xff09;保存一个对象的某个状态&#xff0c;以便在适当的时候恢复对象 备忘录模式属于行为型模式 摘要 1. 意图 在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对…

mockjs学习

1.前言 最近面试发现之前团队协同合作的项目没有mock数据难以向面试官直接展示&#xff0c;所以迟到得来速学一下mockjs。 参考视频&#xff1a;mockJs 妈妈再也不用担心我没有后端接口啦_哔哩哔哩_bilibili 一开始查阅了一些资料&#xff0c;先是看了下EasyMock&#xff0c…

利用websocket +定时器简易的实现一个网络聊天室

其实原理非常简单,就是客户端用户通过websoket来连接websocket服务端。然后服务端,收集每个用户发出的消息, 进而将每条用户的消息通过广播的形式推送到每个连接到服务端的客户端。从而实现用户的实时聊天。 // TODO : 我主要是讲一下实现思路。并未完善其功能。 1.后端 依赖 …

Spring MVC 全局异常处理器

如果不加以异常处理&#xff0c;错误信息肯定会抛在浏览器页面上&#xff0c;这样很不友好&#xff0c;所以必须进行异常处理。 1.异常处理思路 系统的dao、service、controller出现都通过throws Exception向上抛出&#xff0c;最后由springmvc前端控制器交由异常处理器进行异…

Tensorflow2.0+部署(tensorflow/serving)过程备忘记录Windows+Linux

Tensorflow2.0部署&#xff08;tensorflow/serving&#xff09;过程备忘记录 部署思路&#xff1a;采用Tensorflow自带的serving进模型部署&#xff0c;采用容器docker 1.首先安装docker 下载地址&#xff08;下载windows版本&#xff09;&#xff1a;https://desktop.docke…

Jmeter之Ramp-up Period(in seconds)

1、Ramp-up Period概念 &#xff08;in seconds&#xff09;–并发用户启动周期&#xff0c;告知JMeter 要在多长时间内启动全部Vuser用户。 2、为什么需要有“ramp-up period”&#xff0c;立即启动所有的并发用户数不是更好&#xff1f; 对于绝大多数的网址或应用&#xf…