如果有一个深层的子组件需要一个较远的祖先组件中的部分数据,如果实现呢?
1、可使用props沿着组件链逐级传递下去,如图
2、我们可在祖先组件使用provide提供数据,后代组件使用inject注入数据,如图

一、provide(提供)
1、在应用层如何提供
在应用层方面可通过app.provide()为后代提供数据
import { createApp } from 'vue'
const app = createApp({ })
app.provide('message', 'hello!') // message 注入名, 'hello' 值
2、在组件中如何提供
在组合式 API "<script setup>" 中,可通过provide()函数来为后代组件提供数据
<script setup>
import { ref, provide } from 'vue'
const message = 'hello'
const title = ref('博客')
const subtitle = ref('百万博主分享经验')
function changeSubtitle(sub) {
subtitle.value = sub
}
provide('message', message) // 提供固定数据
provide('title', title) // 提供响应式数据
provide('subtitle', subtitle) // 提供响应式数据
provide('changeSubtitle', changeSubtitle) // 为后代组件提供修改响应式数据 subtitle 的函数
</script>
二、inject(注入)
在组合式 API 中,使用inject()函数的返回值来注入祖先组件提供的数据
1、如果提供数据的值是一个ref,注入进来的会是该ref对象,和提供方保持响应式连接
2、如果注入的数据并没有在祖先组件中提供,则会抛出警告,可在inject()函数的第二个参数设置默认值来解决
3、他们可以在JS和视图模板中直接访问
<script setup>
import { inject } from 'vue'
const c_message = inject('message')
const title = inject('title')
const c_subtitle = inject('subtitle')
const c_changeSub = inject('changeSubtitle')
// 祖先组件并未提供 content,则会报警告,设置默认值来解决
const c_content = inject('content', '暂时还未有内容')
</script>
三、依赖注入案例
main.js
// import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
//为所有的组件提供数据
app.provide('message','登录成功')
//provide选项中通过computed函数提供的响应式数据,需要设置此项保证注入会自动解包这个计算属性,但是3.3版本后就不需要了
app.config.unwrapInjectedRef = true
app.mount('#app')
App.vue
<script setup>
import { provide,ref } from 'vue';
import FooterVue from './components/Footer.vue'
let title = '博客'
let subtitle = ref('百万博主分享经验')
function changeSubtitle(sub) {
subtitle.value = sub
}
//为后代组件提供数据
provide('title',title) //提供普通的数据
provide('subtitle',subtitle) //提供响应式数据,自动和注入方保持响应式的连接
provide('changeSubtitle',changeSubtitle) //提供修改响应式数据subtitle的函数
</script>
<!-- 视图区域(view) -->
<template>
<div class="area" style="background-color: red">
<h3>这是APP组件</h3>
副标题:<input type="text" v-model="subtitle">
<FooterVue/>
</div>
</template>
<style>
.area {
padding: 15px;
}
</style>
Footer.vue
<script setup>
import DeepChildVue from './DeepChild.vue';
</script>
<template>
<div class="area" style="background-color: yellow">
<h3>这是Footer组件</h3>
<DeepChildVue/>
</div>
</template>
DeepChild.vue
<script setup>
import { inject } from 'vue';
//注入祖先组件提供的数据
let d_message = inject('message') //应用层提供的数据
let d_title = inject('title') //普通数据
let d_subtitle = inject('subtitle') //ref响应式数据,则d_subtitle也是ref对象
let d_changeSub = inject('changeSubtitle') //函数
let d_content = inject('content') //祖先组件并未提供,则会抛出警告
let d_action = inject('action','关注博客') //祖先组件并未提供,则会抛出警告
function showInjectData() {
console.log('应用层提供的数据message的值:'+d_message)
console.log('APP组件提供的title的值:'+d_title)
console.log('APP组件提供的subtitle的值:'+d_subtitle)
console.log('获取祖先组件提供content的数据(并没有提供):'+d_content)
console.log('获取祖先组件提供action的数据(并没有提供,但是设置默认值):'+d_action)
d_changeSub('EDF')
}
</script>
<template>
<div class="area" style="background-color:pink">
<h3>这是DeepChild组件</h3>
<ul>
<li>应用层提供的数据message的值:{{ d_message }}</li>
<li>APP组件提供的title的值:{{ d_title }}</li>
<li>APP组件提供的subtitle的值:{{ d_subtitle }}</li>
<li>获取祖先组件提供content的数据(并没有提供):{{ d_content }}</li>
<li>获取祖先组件提供action的数据(并没有提供,但是设置默认值):{{ d_action }}</li>
</ul>
<button @click="d_changeSub('ABC')">修改APP组件中subtitle的值</button>
<button @click="showInjectData">在JS中访问注入的数据</button>
</div>
</template>

被折叠的 条评论
为什么被折叠?



