非父子通信: provide和inject

一、核心概念

  1. 作用:允许祖先组件 (provider)向任意层级后代(injector)传递数据,而无需经过每一层 props 逐级下发或事件逐级上报。

  2. 语义:

    • provide:在祖先组件里"声明"要下发的数据。

    • inject:在后代组件里"声明"要接收的数据。

  3. 响应式差异:

    • Vue2 默认不具备响应式联动(provide 的值在运行时变了,后代不会自动更新)。

    • Vue3 只要 provide 的是 ref / reactive 对象,后代就能自动追踪变化。

二、Vue2 示例(Options API)

javascript 复制代码
<template>
  <div>
    <h3>根组件 (Vue2) 主题: {{theme}}</h3>
    <button @click="toggleTheme">切换主题</button>
    <hr>
    <Child/>
  </div>
</template>

<script>
import Child from './Child.vue'

export default {
  components: { Child },
  data() {
    return {
      theme: 'light'          // 普通字符串,非响应式
    }
  },
  provide() {                 // 关键点1:函数写法,才能访问 this
    return {
      theme: this.theme,      // 注意:仅初始化时快照,后续变化不会同步
      toggleTheme: this.toggleTheme
    }
  },
  methods: {
    toggleTheme() {
      this.theme = this.theme === 'light' ? 'dark' : 'light'
    }
  }
}
</script>

子孙组件

javascript 复制代码
<template>
  <div style="margin-left: 40px;">
    <p>孙子组件拿到主题:{{theme}}</p>
    <button @click="toggleTheme">孙子触发切换</button>
  </div>
</template>

<script>
export default {
  inject: ['theme', 'toggleTheme'],   // 关键点2:数组语法
  created() {
    console.log('Vue2 inject 到的数据:', this.theme)
  }
}
</script>

运行结果:

  • 初始能读到 theme;

  • 根组件按钮可切换,但孙子不会自动刷新(非响应式)。

三、Vue3 示例(Composition API)

javascript 复制代码
<template>
  <div>
    <h3>根组件 (Vue3) 主题: {{theme}}</h3>
    <button @click="toggleTheme">切换主题</button>
    <hr>
    <Child/>
  </div>
</template>

<script setup>
import { provide, ref, readonly } from 'vue'
import Child from './Child.vue'

const theme = ref('light')
function toggleTheme() {
  theme.value = theme.value === 'light' ? 'dark' : 'light'
}
// 关键点1:使用 provide(key, value)
provide('theme', readonly(theme))      // 只读保护,防止被随意修改
provide('toggleTheme', toggleTheme)
</script>

子孙组件

javascript 复制代码
<template>
  <div style="margin-left: 40px;">
    <p>孙子组件拿到主题:{{theme}}</p>
    <button @click="toggleTheme">孙子触发切换</button>
  </div>
</template>

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

const theme = inject('theme')            // 关键点2: inject(key, 默认值?)
const toggleTheme = inject('toggleTheme')

// 默认值示例
const user = inject('user', { name: 'Guest' })
</script>

运行结果:

  • 根组件切换按钮,孙子立即同步刷新(响应式)。

四、常见陷阱速查

  1. Vue2 中 provide 写成对象而非函数,导致访问不到实例属性。

  2. 把非响应式字面量(如普通字符串、数字)provide 出去,后期改动后代看不到。

  3. 直接修改 inject 拿到的响应式对象,会绕过单向数据流;最好 provide('xxx', readonly(xxx))

  4. 跨组件层级很深时,provide/inject 比 EventBus 或 Vuex/Pinia 更轻量;但全局状态仍推荐官方状态管理库。

相关推荐
Cobyte13 小时前
模板 DSL 解析器中的状态机设计
前端·javascript·vue.js
颜酱13 小时前
# 02 | 搭骨架:用 LangGraph 编排 12 步工作流(思路)
前端·人工智能·后端
颜酱13 小时前
02 | 搭骨架:用 LangGraph 编排 12 步工作流
前端·人工智能·后端
刘卓航众创芯云服务部14 小时前
Kimi K3复杂任务实测:我把团队最头疼的三个场景全跑了一遍
前端
软件开发技术深度爱好者14 小时前
小学英语单词魔法学园HTML5实现
javascript·html5·英语学习
勉灬之14 小时前
Next.js + Prisma 跨平台部署踩坑记
开发语言·javascript·ecmascript
cll_86924189114 小时前
一个好看的Wordpress博客文字css样式
前端·css·ui
武子康14 小时前
Shippy:确定性工具、会话级 Sandbox 与 Live-Data Eval(4 类收敛 + 7 步实现方案 + 6 类评测指标)
前端·人工智能·后端
糖果店的幽灵14 小时前
langgraph分支之 - 动态分支(Dynamic Branch)
java·前端·javascript·人工智能·langgraph
meilindehuzi_a14 小时前
Workflow 与 Agent 有什么区别:从 LangChain 流水线到智能体决策
前端·人工智能