当前位置: 首页 > news >正文

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

相关文章:

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

一、依赖注入 1、简介 ​ 在前面的笔记中&#xff0c;我们学习过父组件向子组件传递数据时&#xff0c;需要借助props来实现。但如果父组件想要向孙子组件传递数据&#xff0c;那就要连续使用两层props逐级向下传递&#xff0c;如果要接收数据的是更深层的后代组件&#xff0…...

JZ76 删除链表中重复的结点

/*public class ListNode {int val;ListNode next null;ListNode(int val) {this.val val;} } */import java.util.*; public class Solution {public ListNode deleteDuplication(ListNode pHead) {//初步想想法&#xff1a; 弄一个hashmap 然后进行key存储起来。然后 如果存…...

20.2 nginx

20.2 nginx 1. 学习目标2. 介绍2.1 正向代理2.2 反向代理2.3 动态静态资源分离2.4 nginx优缺点3. 安装3.1 Linux安装****************************************************************************************************************************************************…...

MySQL学习Day26——事务基础知识

一、数据库事务概述: 事务是数据库区别于文件系统的重要特性之一,事务会让数据始终保持一致性,能通过事务机制恢复到某个时间点,可以保证提交到数据库的修改不会因为系统崩溃而丢失 1.查看引擎支持事务的情况:只有InnoDB存储引擎支持事务 SHOW ENGINES; 2.基本概念: 事…...

three.js 射线Ray,三维空间中绘制线框

效果&#xff1a; 代码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs"></div> <div>{{ res1 }}</div> <div>{{ res2 }}</div><…...

【Demo】游戏小地图

简介 该Demo基于2D关卡随机生成项目进行实现&#xff0c;旨在初步探索游戏小地图的制作。 演示 MiniMapDemo 资源下载 百度网盘&#xff08;提取码&#xff1a;1314&#xff09; 如果这篇文章对你有帮助&#xff0c;请给作者点个赞吧&#xff01;...

代码随想录算法训练营Day39 || leetCode 762.不同路径 || 63. 不同路径 II

62.不同路径 每一位的结果等于上方与左侧结果和 class Solution { public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m,vector(n,0));for (int i 0; i < m; i) dp[i][0] 1;for (int j 0; j < n; j) dp[0][j] 1;for (int i 1; i < m; …...

Qt中parent()函数的使用

情景(需求)抽象&#xff1a; A类对象是B类对象的成员变量。 B类对象是A类对象的父亲。 A类对象中包含按钮&#xff0c;点击按钮&#xff0c;调用B类的成员函数。 示例&#xff1a; A类&#xff1a; #pragma once#include <QWidget> #include "ui_QtWidgetsCla…...

Python基础学习(5)流程控制

文章目录 一. 程序三大执行流程二. 分支结构1.单分支结构(if)2.双分支结构(if..else)3.多分支结构(if..elif..else) 二,缩进(tab键)三,循环结构1.while循环2.for循环①遍历字典 五.break&#xff0c;continue和pass语句1.break&#xff0c;continue2.pass Python基础学习(1)基本…...

代码随想录刷题笔记 DAY 42 | 最后一块石头的重量 II No.1049 | 目标和 No.494 | 一和零 No.474

文章目录 Day 4301. 最后一块石头的重量 II&#xff08;No. 1049&#xff09;<1> 题目<2> 笔记<3> 代码 02. 目标和&#xff08;No. 494&#xff09;<1> 题目<2> 笔记<3> 代码 03. 一和零&#xff08;No. 474&#xff09;<1> 题目&l…...

793.高精度乘法(acwing)

文章目录 793.高精度乘法题目描述高精度乘法 793.高精度乘法 题目描述 给定两个正整数A和B&#xff0c;请你计算A * B的值。 输入格式 共两行&#xff0c;第一行包含整数A&#xff0c;第二行包含整数B。 输出格式 共一行&#xff0c;包含A * B的值。 数据范围 1≤A的长度≤…...

考研经验|如何从考研失败中走出来?

对我来说&#xff0c;太丢人了 其实我在本科的时候在同学眼中&#xff0c;一直很优秀&#xff0c;每年奖学金必有我的&#xff0c;国家励志奖学金&#xff0c;国家奖学金&#xff0c;这种非常难拿的奖学金&#xff0c;我也拿过&#xff0c;本科期间学校有一个公费去新西兰留学的…...

SpringBoot如何修改pom依赖的默认版本号

1、找到SpringBoot父工程依赖。 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version> </parent>2、ctrl 鼠标左键点击<artifact…...

UDP与TCP:了解这两种网络协议的不同之处

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

String、StringBuffer基本用法

一、StringBuffer基本用法 1.append():字符串连接操作 StringBuffer sb new StringBuffer();sb.append("a");sb.append("b");sb.append("c");sb.append("哈哈").append("d");System.out.println(sb);2.insert():在任意位…...

蓝桥杯刷题5--GCD和LCM

目录 1. GCD 1.1 性质 1.2 代码实现 2. LCM 2.1 代码实现 3. 习题 3.1 等差数列 3.2 Hankson的趣味题 3.3 最大比例 3.4 GCD 1. GCD 整数a和b的最大公约数是能同时整除a和b的最大整数&#xff0c;记为gcd(a, b) 1.1 性质 GCD有关的题目一般会考核GCD的性质。   …...

LVS+Keepalived 高可用负载均衡集群

一. 高可用集群的相关知识 1.1 高可用&#xff08;HA&#xff09;集群和普通集群的比较 ① 普通集群 普通的群集的部署是通过一台度器控制调配多台节点服务器进行业务请求的处理&#xff0c;但是仅仅是一台调度器&#xff0c;就会存在极大的单点故障风险&#xff0c;当该调度…...

【RK3288 Android6, T8PRO 快捷按键 gpio 配置上拉输入】

文章目录 【RK3288 Android6&#xff0c; T8PRO 快捷按键 gpio 配置上拉输入】需求开发过程尝试找到没有用的上拉gpio尝试修改pwm1的gpio的默认上拉模式 改动 【RK3288 Android6&#xff0c; T8PRO 快捷按键 gpio 配置上拉输入】 需求 T8pro想要模仿T10 的 快捷按键&#xff…...

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:LoadingProgress)

用于显示加载动效的组件。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 LoadingProgress() 创建加载进展组件。 从API version 9开始&#xff0c;该接口支持在ArkTS卡片中使…...

隐私与创新的交汇点:Partisia Blockchain 重绘技术蓝图

正当我们在这个信息泛滥的时代寻找稳固的信任锚点时&#xff0c;区块链技术应运而生&#xff0c;然而&#xff0c;正如任何科技革命都会遇到的挑战&#xff0c;一个重要的问题摆在了我们面前&#xff1a;如何在不牺牲个人隐私的前提下&#xff0c;享受区块链技术带来的好处&…...

每日一题day1(Leetcode 76最小覆盖子串)

1.题目解析 1.该题“讲人话”就是在一个字符串s中找到一个最短的能够涵盖子串所有字符的子串 2.解法 解法1&#xff08;暴力枚举hash表&#xff09; class Solution { public:string minWindow(string s, string t) {int m s.size();int n t.size();if (m < n)return &quo…...

500W无桥PFC开关电源设计资料详解:硬件原理与C语言源码揭秘

500W 无桥PFC开关电源设计资料&#xff0c;C语言源码。 硬件原理 500W 无桥PFC开关电源设计资料&#xff0c;C语言源码。 硬件原理无桥PFC这玩意儿现在在电源圈子里火得不行&#xff0c;相比传统拓扑&#xff0c;它直接把整流桥给扬了&#xff0c;效率提升不是一点半点。今天…...

零基础入门:计算机视觉需要哪些数学基础?如何高效学习线性代数和概率论?

零基础入门&#xff1a;计算机视觉需要哪些数学基础&#xff1f;如何高效学习线性代数和概率论&#xff1f; 标签&#xff1a;#计算机视觉、#线性代数、#人工智能、#深度学习、#自然语言处理、#神经网络、#机器学习### 一、痛点引入&#xff1a;为什么很多人怕CV数学&#xff1…...

S2-Pro入门Python编程:零基础到搭建第一个AI应用

S2-Pro入门Python编程&#xff1a;零基础到搭建第一个AI应用 1. 为什么选择S2-Pro学习Python 学习编程最难的不是语法本身&#xff0c;而是如何保持兴趣和看到实际效果。传统学习方式往往需要先花大量时间配置环境、安装软件&#xff0c;还没开始写代码就已经被各种报错劝退。…...

告别SVN!5人小团队用Gitea+SQLite在内网轻松搞定Git代码仓(附Windows/Linux双平台配置)

告别SVN&#xff01;5人小团队用GiteaSQLite在内网轻松搞定Git代码仓&#xff08;附Windows/Linux双平台配置&#xff09; 在小型技术团队中&#xff0c;版本控制系统往往面临两难选择&#xff1a;功能齐全的企业级方案太重&#xff0c;而轻量级工具又缺乏协作能力。我曾带领一…...

YOLO-v5优化指南:从mAP指标出发,3步提升模型检测效果

YOLO-v5优化指南&#xff1a;从mAP指标出发&#xff0c;3步提升模型检测效果 1. 理解mAP与模型性能的关系 1.1 mAP的核心价值 在目标检测任务中&#xff0c;mAP&#xff08;mean Average Precision&#xff09;是最关键的评估指标之一。它综合反映了模型在不同类别上的检测精…...

探索DebToIPA核心技术:解密.deb到.ipa的架构突破与移动应用格式革命

探索DebToIPA核心技术&#xff1a;解密.deb到.ipa的架构突破与移动应用格式革命 【免费下载链接】DebToIPA Convert .deb apps to .ipa files, on iOS, locally 项目地址: https://gitcode.com/gh_mirrors/de/DebToIPA 在移动应用生态系统的技术演进中&#xff0c;跨平台…...

AlienFX Tools:彻底掌控你的Alienware设备,告别臃肿原厂软件

AlienFX Tools&#xff1a;彻底掌控你的Alienware设备&#xff0c;告别臃肿原厂软件 【免费下载链接】alienfx-tools Alienware systems lights, fans, and power control tools and apps 项目地址: https://gitcode.com/gh_mirrors/al/alienfx-tools 你是否对Alienware…...

如何突破数字图书馆借阅限制:Internet Archive Downloader技术深度解析

如何突破数字图书馆借阅限制&#xff1a;Internet Archive Downloader技术深度解析 【免费下载链接】internet_archive_downloader A chrome/firefox extension that download books from Internet Archive(archive.org) and HathiTrust Digital Library (hathitrust.org) 项…...

从零开始掌握ky:基于fetch的轻量级HTTP客户端实战指南

1. 为什么你需要ky这个HTTP客户端&#xff1f; 如果你经常用JavaScript写前端项目&#xff0c;肯定对原生fetch不陌生。这个浏览器自带的API确实解决了XMLHttpRequest的很多痛点&#xff0c;但用久了就会发现它有不少"反人类"设计。比如&#xff1a; 必须手动检查res…...