vue3探索——组件通信之依赖注入

  • vue3探索——组件通信之依赖注入已关闭评论
  • 110 次浏览
  • A+
所属分类:Web前端
摘要

通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props。想象一下这样的结构:有一些多层级嵌套的组件,形成了一颗巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦:


背景

通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props。想象一下这样的结构:有一些多层级嵌套的组件,形成了一颗巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦:

vue3探索——组件通信之依赖注入

对于这种组件使用结构,vue3给我们提供了另外一种传参方式,那就是依赖注入。一个父组件相对于其所有的后代组件,会作为依赖提供者(provide)。任何后代的组件树,无论层级有多深,都可以注入(inject)由父组件提供给整条链路的依赖。

vue3探索——组件通信之依赖注入

基础使用

依赖提供者provide()

provide的使用非常简单,下面给出代码。

<script setup lang="ts"> // 1-引入 import { ref, provide } from 'vue';  const param = ref();  // 2-使用 provide('mark', param); </script> 

provide()函数需要传入两个参数:

  • 第一个参数被称为注入名,可以是一个字符串或是一个 Symbol。后代组件会用注入名来查找期望注入的值。一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值。
  • 第二个参数是提供的值,值可以是任意类型,包括响应式的状态,比如一个 ref。提供的响应式状态使后代组件可以由此和提供者建立响应式的联系。

? 增强功能:除了在一个组件中提供依赖,我们还可以在整个应用层面提供依赖,类似于vue2中挂载在vue实例的原型对象上

import { createApp } from 'vue'  const app = createApp({})  app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!') 

在应用级别提供的数据在该应用内的所有组件中都可以注入。这在你编写插件时会特别有用,因为插件一般都不会使用组件形式来提供值。

注入inject()

要注入上层组件提供的数据,需使用 inject() 函数:

<script setup lang="ts"> // 1-引入 import { inject } from 'vue';  // 2-使用 const param = inject('mark'); // 第二个参数可以设置注入**默认值**,防止祖先组件没有提供依赖而造成报错 const param2 = inject('mark2', '默认值'); </script> 

❗ 注意,不使用<script setup> 的话,需要在setup()函数中使用provide()inject()

import { provide } from 'vue'  export default {   setup() {     provide(/* 注入名 */ 'message', /* 值 */ 'hello!')   } } 
import { inject } from 'vue'  export default {   setup() {     const message = inject('message')     return { message }   } } 

实战

// src/App.vue <template>     <div class="dad">         <!-- 1000元 -->         <h1>我是父组件,我有{{ money }}元</h1>         <!-- 使用子组件 -->         <son />     </div> </template>  <script setup lang="ts"> // 引入子组件 import son from './components/son.vue'; // 引入vue API import { ref, provide } from 'vue';  // 1-父组件响应式数据 const money = ref(1000);  // 向后面的组件提供依赖 provide('Pmoney', money); </script>  <style lang="scss" scoped> .dad {     width: 600px;     height: 600px;     background-color: skyblue;     display: flex;     flex-direction: column;     justify-content: center;     align-items: center; } </style> 
// src/components/son.vue <template>     <div class="son">         <h2>我是子组件</h2>         <!-- 使用孙组件 -->         <grandson />     </div> </template>  <script setup lang="ts"> // 引入孙组件 import grandson from './grandson.vue'; </script>  <style lang="scss" scoped> .son {     height: 400px;     width: 400px;     background-color: pink;     display: flex;     flex-direction: column;     justify-content: center;     align-items: center; } </style> 
// src/components/grandson.vue <template>     <div class="grandson">         <h3>我是孙组件,我爷爷有{{ money }}元</h3>     </div> </template>  <script setup lang="ts"> // 引入 inject import { inject } from 'vue';  // 2-注入祖先组件的依赖 const money = inject('Pmoney'); </script>  <style lang="scss" scoped> .grandson {     width: 200px;     height: 200px;     background-color: aqua; } </style>