1、Prop 逐级透传问题
通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props。想象一下这样的结构:有一些多层级嵌套的组件,形成了一棵巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦:
注意,虽然这里的 <Footer> 组件可能根本不关心这些 props,但为了使 <DeepChild> 能访问到它们,仍然需要定义并向下传递。如果组件链路非常长,可能会影响到更多这条路上的组件。这一问题被称为“prop 逐级透传”,显然是我们希望尽量避免的情况。
2、provide 和 inject 的使用
provide 和 inject 可以帮助我们解决这一问题。一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
provide() 函数:为组件后代提供数据。
inject() 函数:要注入上层组件提供的数据。
语法格式:
<script setup>
//第一步:导入函数
import { provide, inject } from 'vue';
//第二步:使用provide函数,传递数据
provide('key', '数据');
//第三步:使用inject函数,接收数据
const data = inject('key');
</script>
2.1 跨层组件的数据传递与接收
【实例】使用依赖注入 provide 和 inject 函数,实现跨层级组件之间数据的传递与接收。
(1)修改 App.vue 根组件文件,实现爷爷组件功能,并使用 provide 传递数据。
<template>
<fieldset>
<legend>爷爷组件</legend>
<!-- 使用组件 -->
<ParentComponent></ParentComponent>
</fieldset>
</template>
<!-- 使用 <script setup> 语法糖 -->
<script setup>
//导入组件,使用 <script setup> 语法糖,导入的组件将会自动执行注册
import ParentComponent from '@/components/ParentComponent.vue';
import { reactive, provide } from 'vue';
// 使用 reactive 创建响应式的对象
const blogInfo = reactive({
blogName: '您好,欢迎访问 pan_junbiao的博客',
blogUrl: 'https://blog.csdn.net/pan_junbiao'
});
//核心代码:使用provide函数,传递数据
provide('blogName-key', blogInfo.blogName);
provide('blogUrl-key', blogInfo.blogUrl);
</script>
(2)创建 ParentComponent.vue 父组件。
<template>
<fieldset>
<legend>父组件</legend>
<!-- 使用组件 -->
<ChildComponent></ChildComponent>
</fieldset>
</template>
<!-- 使用 <script setup> 语法糖 -->
<script setup>
//导入组件,使用 <script setup> 语法糖,导入的组件将会自动执行注册
import ChildComponent from '@/components/ChildComponent.vue'
</script>
(3)创建 ChildComponent.vue 子组件,并使用 inject 接收爷爷组件传递的数据。
<template>
<fieldset>
<legend>子组件</legend>
<h3>子组件接收到爷爷组件传递的数据:</h3>
<p>博客信息:{{ blogName }}</p>
<p>博客信息:{{ blogUrl }}</p>
</fieldset>
</template>
<!-- 使用 <script setup> 语法糖 -->
<script setup>
import { ref , inject} from 'vue';
// 使用 ref 创建响应式的对象
const blogName = ref('');
const blogUrl = ref('');
// 核心代码:使用inject函数,接收数据
blogName.value = inject('blogName-key');
blogUrl.value = inject('blogUrl-key');
</script>
执行结果:
2.3 跨层组件的数据修改
provide 和 inject 函数可以传递和接收数据,同时也可以传递和接收一个方法。通过传递与接收一个方法,可以实现跨层组件的数据修改。
【实例】使用依赖注入 provide 和 inject 函数,实现跨层级组件之间数据的修改。
(1)修改 App.vue 根组件文件,实现爷爷组件功能,并使用 provide 传递数据。
<template>
<fieldset>
<legend>爷爷组件</legend>
<p>计数结果:{{ count }}</p>
<!-- 使用组件 -->
<ParentComponent></ParentComponent>
</fieldset>
</template>
<!-- 使用 <script setup> 语法糖 -->
<script setup>
//导入组件,使用 <script setup> 语法糖,导入的组件将会自动执行注册
import ParentComponent from '@/components/ParentComponent.vue';
import { ref, provide } from 'vue';
// 使用 ref 创建响应式的对象
const count = ref(0);
//定义一个方法:计数功能
const setCountFun = () => {
count.value++;
}
//核心代码:使用provide函数,传递一个方法
provide('setCountFun-key', setCountFun);
</script>
(2)创建 ParentComponent.vue 父组件。
<template>
<fieldset>
<legend>父组件</legend>
<!-- 使用组件 -->
<ChildComponent></ChildComponent>
</fieldset>
</template>
<!-- 使用 <script setup> 语法糖 -->
<script setup>
//导入组件,使用 <script setup> 语法糖,导入的组件将会自动执行注册
import ChildComponent from '@/components/ChildComponent.vue'
</script>
(3)创建 ChildComponent.vue 子组件,并使用 inject 接收爷爷组件传递的一个方法。
<template>
<fieldset>
<legend>子组件</legend>
<h3>子组件接收到爷爷组件传递的一个方法:</h3>
<button @click="setCountFun">修改爷爷组件的数据</button>
</fieldset>
</template>
<!-- 使用 <script setup> 语法糖 -->
<script setup>
import { inject } from 'vue';
// 核心代码:使用inject函数,接收一个方法
const setCountFun = inject('setCountFun-key');
</script>
执行结果: