Vue中的provide与inject

文章目录

      • [provide 与 inject 核心功能](#provide 与 inject 核心功能)
      • [Vue2 中的用法](#Vue2 中的用法)
        • [1. 基本用法](#1. 基本用法)
        • [2. 响应式处理(Vue2 关键注意点)](#2. 响应式处理(Vue2 关键注意点))
      • [Vue3 中的用法](#Vue3 中的用法)
        • [1. 基本用法(`<script setup>`)](#1. 基本用法(<script setup>))
        • [2. 响应式处理(Vue3 优势)](#2. 响应式处理(Vue3 优势))
        • [3. 类型提示(TypeScript)](#3. 类型提示(TypeScript))
      • 使用场景
      • 基本原理
      • 总结

provide 与 inject 核心功能

provideinject 是 Vue 提供的跨组件通信方案,用于解决多层级组件(父子、祖孙、更深层级)之间的数据传递问题。其核心功能是:

  • provide:在父组件(或祖先组件)中定义需要共享的数据或方法,作为"提供者"。
  • inject:在子组件(或后代组件)中声明需要接收的数据或方法,作为"消费者"。
  • 特点:无需通过 props 逐级传递(避免"props 钻取"),直接跨层级通信,且不受层级深度限制。

Vue2 中的用法

Vue2 中 provideinject 以组件选项(Options API)的形式使用。

1. 基本用法
  • 父组件(提供者) :通过 provide 选项定义需要共享的数据(对象或返回对象的函数)。
  • 子组件(消费者) :通过 inject 选项声明需要注入的数据(字符串数组或配置对象)。

示例:

html 复制代码
<!-- 父组件(Grandparent.vue) -->
<template>
  <div>父组件</div>
  <Parent />
</template>

<script>
import Parent from './Parent.vue'
export default {
  components: { Parent },
  // provide 可以是对象或函数(函数更灵活,可访问 this)
  provide() {
    return {
      theme: 'dark', // 非响应式数据
      user: this.currentUser // 可传递组件内数据(需注意响应式)
    }
  },
  data() {
    return {
      currentUser: { name: '张三' }
    }
  }
}
</script>


<!-- 子组件(Child.vue,层级:Grandparent -> Parent -> Child) -->
<template>
  <div>
    主题:{{ theme }}<br>
    用户名:{{ user.name }}
  </div>
</template>

<script>
export default {
  // inject 可以是字符串数组(直接指定 key)
  // inject: ['theme', 'user']

  // 也可以是对象(支持默认值、重命名)
  inject: {
    theme: {
      from: 'theme', // 对应 provide 的 key(可选,默认与属性名一致)
      default: 'light' // 未提供时的默认值
    },
    userName: {
      from: 'user', // 注入 user 数据
      default: () => ({ name: '匿名' }) // 默认值为对象时需用函数返回
    }
  }
}
</script>
2. 响应式处理(Vue2 关键注意点)

Vue2 中 provide 提供的数据默认是非响应式的。若需要响应式,需通过以下方式:

  • 传递组件的 datacomputed 中的响应式对象(因为 data 中的属性本身是响应式的)。
  • 避免直接传递基本类型(如字符串、数字),建议包裹在对象中。

示例(响应式改造):

html 复制代码
<!-- 父组件 -->
provide() {
  return {
    // 传递响应式对象(data 中的属性)
    appState: this.appState
  }
},
data() {
  return {
    appState: {
      theme: 'dark', // 响应式
      user: { name: '张三' }
    }
  }
}

<!-- 子组件修改后,父组件会同步更新 -->
this.appState.theme = 'light' // 有效(响应式)

Vue3 中的用法

Vue3 中 provideinject 主要通过 Composition API 实现(在 setup 函数或 <script setup> 中使用),同时支持响应式传递。

1. 基本用法(<script setup>
  • vue 导入 provideinject 函数。
  • provide(key, value):第一个参数为 key(字符串或 Symbol),第二个参数为要共享的值。
  • inject(key, defaultValue):第一个参数为 key,第二个参数为可选默认值。

示例:

html 复制代码
<!-- 父组件(Grandparent.vue) -->
<template>
  <div>父组件</div>
  <Parent />
</template>

<script setup>
import { provide } from 'vue'
import Parent from './Parent.vue'

// 提供数据(可直接提供基本类型或对象)
provide('theme', 'dark')
// 提供响应式数据(ref/reactive)
const user = { name: '张三' }
provide('user', user)
</script>


<!-- 子组件(Child.vue) -->
<template>
  <div>
    主题:{{ theme }}<br>
    用户名:{{ user.name }}
  </div>
</template>

<script setup>
import { inject } from 'vue'

// 注入数据(指定 key)
const theme = inject('theme', 'light') // 第二个参数为默认值
const user = inject('user', () => ({ name: '匿名' })) // 默认值为对象时建议用函数
</script>
2. 响应式处理(Vue3 优势)

Vue3 中,若 provide 传递的是 响应式数据refreactive),则 inject 后的数据会保持响应式(修改时自动更新)。

示例(响应式传递):

html 复制代码
<!-- 父组件 -->
<script setup>
import { provide, ref, reactive } from 'vue'

// ref 响应式(基本类型)
const theme = ref('dark')
provide('theme', theme)

// reactive 响应式(对象)
const user = reactive({ name: '张三' })
provide('user', user)

// 父组件修改,子组件会同步更新
setTimeout(() => {
  theme.value = 'light'
  user.name = '李四'
}, 2000)
</script>


<!-- 子组件 -->
<script setup>
import { inject } from 'vue'

const theme = inject('theme')
const user = inject('user')

// 子组件修改响应式数据,父组件也会同步(若需禁止,可用 readonly)
// const user = inject('user') // 可修改
// const user = readonly(inject('user')) // 只读,防止子组件修改
</script>
3. 类型提示(TypeScript)

Vue3 中可通过 InjectionKey 实现类型约束(避免 key 冲突和类型错误):

typescript 复制代码
// keys.ts
import type { InjectionKey } from 'vue'

export const themeKey: InjectionKey<string> = Symbol('theme')
export const userKey: InjectionKey<{ name: string }> = Symbol('user')


// 父组件
import { provide } from 'vue'
import { themeKey, userKey } from './keys'

provide(themeKey, 'dark') // 类型约束:必须是 string
provide(userKey, { name: '张三' }) // 类型约束:必须符合 { name: string }


// 子组件
import { inject } from 'vue'
import { themeKey, userKey } from './keys'

const theme = inject(themeKey, 'light') // 类型:string
const user = inject(userKey) // 类型:{ name: string } | undefined

使用场景

  1. 多层级共享配置:如主题(深色/浅色)、语言切换、全局权限等(跨组件共享的静态或低频变化数据)。
  2. 插件/库内部通信:插件向子组件传递配置或方法(如 UI 组件库中,父组件向深层级子组件传递尺寸、样式等)。
  3. 避免 props 钻取 :当组件层级较深(如 5 层以上),用 provide/inject 替代 props 逐级传递,减少代码冗余。

不适合的场景

  • 简单父子组件通信(直接用 props/emits 更清晰)。
  • 高频变化或需要严格状态管理的数据(建议用 Pinia/Vuex,便于追踪状态变化)。

基本原理

provideinject 基于 Vue 的组件实例树实现,核心逻辑如下:

  1. 数据存储 :每个组件实例(vm)会维护一个 provides 对象,用于存储当前组件通过 provide 提供的数据。
  2. 查找链构建 :当组件初始化时,会继承父组件的 provides(形成一个原型链/查找链)。即:子组件的 provides 以父组件的 provides 为原型,以此类推。
  3. 注入查找 :当子组件通过 inject 查找数据时,会沿着组件实例的 provides 链向上遍历,直到找到匹配的 key 或到达根组件。

响应式原理

  • 若提供的是响应式数据(Vue2 中 data 里的对象,Vue3 中 ref/reactive),则依赖该数据的组件会被纳入响应式依赖追踪。当数据变化时,所有依赖组件会重新渲染。

总结

特性 Vue2(Options API) Vue3(Composition API)
用法 组件选项 provide(对象/函数)、inject(数组/对象) 导入 provide/inject 函数,在 setup 中调用
响应式 需手动传递响应式对象(如 data 中的属性) 原生支持 ref/reactive 响应式传递
类型支持 较弱(需手动注释) 可通过 InjectionKey 实现强类型约束
灵活性 依赖组件选项,灵活性较低 可在 setup 中动态提供/注入,灵活性更高

核心作用一致:跨层级通信,减少 props 传递成本,适用于共享低频变化的全局配置或插件内部通信。

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax