Vue学习:21-依赖注入

如果有一个深层的子组件需要一个较远的祖先组件中的部分数据,如果实现呢?

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值