Vue组件花式传值:祖孙组件如何愉快地聊天?

大家好,我是小杨,一个写了6年前端的老油条。今天咱们聊聊Vue里一个经典问题:多级嵌套组件之间怎么传值

你是不是也遇到过这种场景:

  • 爷爷组件想直接给孙子组件发个红包(数据),结果爸爸组件一脸懵:"关我啥事?"
  • 兄弟组件想互相喊话,却只能靠老爸当传话筒,麻烦得要死......

别急!今天我就用几个接地气的例子,带你解锁Vue组件通信的N种姿势,让你家的组件们从此愉快聊天!


1. 父子组件:Props & $emit(基础版)

适用场景:爸爸给儿子发零花钱,儿子收到后喊一声"谢谢爸"。

vue 复制代码
<!-- 父组件 -->
<template>
  <Child :money="100" @say-thanks="handleThanks" />
</template>

<script>
export default {
  methods: {
    handleThanks(msg) {
      console.log(msg); // 输出:"我收到100块啦!"
    }
  }
}
</script>

<!-- 子组件 -->
<template>
  <button @click="thankParent">点我收钱</button>
</template>

<script>
export default {
  props: ['money'],
  methods: {
    thankParent() {
      this.$emit('say-thanks', `我收到${this.money}块啦!`);
    }
  }
}
</script>

关键点

  • 父传子用 props,子传父用 $emit
  • 缺点:如果组件嵌套太深(比如爷爷→爸爸→儿子→孙子...),props 会变成"击鼓传花",中间组件被迫当工具人。

2. attrs & listeners(隐身传值)

适用场景:爷爷想偷偷给孙子塞红包,不想让爸爸知道。

vue 复制代码
<!-- 爷爷组件 -->
<Grandpa>
  <Dad :secret-money="200" />
</Grandpa>

<!-- 爸爸组件(不处理props,直接透传) -->
<template>
  <Son v-bind="$attrs" /> <!-- $attrs包含所有未被props接收的属性 -->
</template>

<!-- 孙子组件 -->
<script>
export default {
  props: ['secretMoney'],
  created() {
    console.log(this.secretMoney); // 输出:200
  }
}
</script>

关键点

  • $attrs 可以绕过中间组件,直接传递未被接收的 props。
  • 类似 $listeners 可以透传事件。

3. provide / inject(家族信托基金)

适用场景:爷爷给所有子孙后代发家传宝刀(数据),谁需要谁拿。

vue 复制代码
<!-- 爷爷组件 -->
<script>
export default {
  provide() {
    return {
      familyWeapon: '屠龙宝刀'
    };
  }
}
</script>

<!-- 孙子组件(或任意后代) -->
<script>
export default {
  inject: ['familyWeapon'],
  created() {
    console.log(this.familyWeapon); // 输出:"屠龙宝刀"
  }
}
</script>

关键点

  • 数据跨层级直达,不用一层层传递。
  • 但慎用!容易导致数据来源不清晰,适合全局配置(比如主题、用户信息)。

4. Event Bus(微信群聊)

适用场景:任意组件之间随时喊话,比如兄弟组件、远房表亲组件。

js 复制代码
// 创建一个Event Bus(通常单独放一个文件)
import Vue from 'vue';
export const eventBus = new Vue();

// 组件A(发消息)
eventBus.$emit('send-msg', '今晚开黑吗?');

// 组件B(收消息)
eventBus.$on('send-msg', msg => {
  console.log(`我收到消息:${msg}`); // 输出:"今晚开黑吗?"
});

关键点

  • 简单粗暴,但事件多了容易乱。
  • 记得在组件销毁时移除监听(beforeDestroy 里用 $off)。

5. Vuex(家族中央仓库)

适用场景:全家共享的数据,比如家族存款、祖传秘方。

js 复制代码
// store.js
export default new Vuex.Store({
  state: { familySavings: 10000 },
  mutations: {
    withdraw(state, amount) {
      state.familySavings -= amount;
    }
  }
});

// 任意组件消费
<script>
export default {
  computed: {
    savings() {
      return this.$store.state.familySavings;
    }
  },
  methods: {
    takeMoney() {
      this.$store.commit('withdraw', 500);
      console.log(`我取了500,还剩${this.savings}`); 
    }
  }
}
</script>

关键点

  • 集中管理状态,适合中大型项目。
  • 小项目用可能杀鸡用牛刀。

总结:怎么选?

方式 适用场景 一句话点评
Props & $emit 父子组件简单通信 基础操作,但嵌套深了会累
attrs & listeners 跨层透传属性/事件 中间商不赚差价
provide / inject 祖先→后代远程投喂 慎用,容易找不到数据源头
Event Bus 任意组件通信 小项目可行,大项目易混乱
Vuex 复杂状态共享 全家桶的尊严,但需要学规则

最后吐槽

有次我用 props 传了5层组件,最后发现传了个寂寞------代码像意大利面条一样绕。后来学了 provide/inject,直呼真香!

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
lightgis1 小时前
16openlayers加载COG(云优化Geotiff)
前端·javascript·html·html5
小飞大王6661 小时前
TypeScript核心类型系统完全指南
前端·javascript·typescript
你的人类朋友3 小时前
✍️记录自己的git分支管理实践
前端·git·后端
合作小小程序员小小店3 小时前
web网页开发,在线考勤管理系统,基于Idea,html,css,vue,java,springboot,mysql
java·前端·vue.js·后端·intellij-idea·springboot
防火墙在线3 小时前
前后端通信加解密(Web Crypto API )
前端·vue.js·网络协议·node.js·express
Jacky-0083 小时前
Node + vite + React 创建项目
前端·react.js·前端框架
CoderYanger4 小时前
前端基础——CSS练习项目:百度热榜实现
开发语言·前端·css·百度·html·1024程序员节
i_am_a_div_日积月累_4 小时前
10个css更新
前端·css
她是太阳,好耀眼i5 小时前
Nvm 实现vue版本切换
javascript·vue.js·ecmascript
蒲公英10015 小时前
在wps软件的word中使用js宏命令设置表格背景色
javascript·word·wps