一、组件间通信的概念
在 Vue 中,组件(Component) 是最核心的概念之一。每个 .vue 文件都可以视为一个独立的组件。
而 通信(Communication) 是指一个组件如何将信息传递给另一个组件。
通俗地说:
组件间通信,就是不同组件之间如何共享数据、触发行为、进行信息交互的过程。
例如:当我们使用 UI 框架中的 table 组件时,需要向它传入 data 数据,这个“传值”的过程本质上就是一种组件通信。
二、组件间通信解决了什么问题?
在实际开发中,每个组件都有自己的作用域,数据默认是相互隔离的。但我们经常希望:
- 父组件能把数据传给子组件;
- 子组件能向父组件反馈事件或数据;
- 两个兄弟组件能共享状态;
- 甚至是跨层级(祖孙、非亲缘)组件之间的数据共享。
这正是组件通信的意义所在:
让组件之间能够协作、共享数据,从而构成一个有机、完整的应用系统。
三、组件间通信的分类
按照组件关系,通信可分为以下几种:
- 父子组件通信
- 兄弟组件通信
- 祖孙组件通信
- 非关系组件通信
简单关系图如下:
1Parent 2 ├── Child A 3 └── Child B 4 └── GrandChild 5
四、Vue 中 8 种常见通信方案
下面是 Vue2 / Vue3 通用的 8 种通信方式,并在最后补充两者的区别。
1. props 传递数据(父 → 子)
适用场景: 父组件向子组件传值。
子组件定义:
1export default { 2 props: { 3 name: String, 4 age: { 5 type: Number, 6 default: 18, 7 required: true 8 } 9 } 10} 11
父组件使用:
1<Child name="Jack" :age="18" /> 2
📘 Vue3 区别:
Vue3 支持在 <script setup> 中使用 defineProps:
1const props = defineProps({ 2 name: String, 3 age: Number 4}) 5
2. $emit 触发自定义事件(子 → 父)
适用场景: 子组件向父组件传递数据或事件。
子组件:
1this.$emit('add', good) 2
父组件:
1<Child @add="cartAdd($event)" /> 2
📘 Vue3 区别:
Vue3 使用 defineEmits:
1const emit = defineEmits(['add']) 2emit('add', good) 3
3. ref 获取子组件实例(父 → 子)
适用场景: 父组件想直接访问子组件实例或方法。
父组件:
1<Child ref="foo" /> 2
1this.$refs.foo.someMethod() 2
📘 Vue3 区别:
Vue3 的 ref 通过 setup 中的 ref() 引用,访问方式为 childRef.value。
4. EventBus 事件总线(兄弟组件)
适用场景: 兄弟组件之间传值。
Bus.js:
1import Vue from 'vue' 2export const Bus = new Vue() 3
发送方:
1Bus.$emit('foo', data) 2
接收方:
1Bus.$on('foo', (data) => { console.log(data) }) 2
📘 Vue3 区别:
Vue3 没有 $on/$off,可用第三方库(如 mitt)实现轻量事件总线:
1import mitt from 'mitt' 2export const bus = mitt() 3 4bus.emit('foo', data) 5bus.on('foo', handler) 6
5. parent/parent / parent/root(祖辈 → 后代)
适用场景: 通过组件实例树访问父组件或根组件方法。
1this.$parent.someMethod() 2this.$root.globalFn() 3
📘 Vue3 区别:
仍可用,但在 Composition API 下不推荐,应优先使用 provide/inject。
6. attrs与attrs 与 attrs与listeners(祖先 → 子孙)
适用场景: 批量向下传递属性与事件。
1<!-- Parent.vue --> 2<Child2 msg="hello" @some-event="handleEvent" /> 3 4<!-- Child2.vue --> 5<Grandson v-bind="$attrs" v-on="$listeners" /> 6 7<!-- Grandson.vue --> 8<div @click="$emit('some-event', 'from grandson')"> 9 {{ msg }} 10</div> 11
📘 Vue3 区别:
Vue3 将 $listeners 合并入 $attrs,事件监听器自动包含其中:
1<Grandson v-bind="$attrs" /> 2
7. Provide / Inject(祖孙通信)
适用场景: 祖先组件向任意深度的后代组件传递数据。
祖先组件:
1provide() { 2 return { 3 foo: 'foo' 4 } 5} 6
后代组件:
1inject: ['foo'] 2
📘 Vue3 区别:
Vue3 使用 Composition API:
1// 祖先 2import { provide } from 'vue' 3provide('foo', 'foo') 4 5// 后代 6import { inject } from 'vue' 7const foo = inject('foo') 8
8. Vuex(或 Pinia)(全局状态管理)
适用场景: 复杂组件关系、跨层级状态共享。
Vuex 核心概念:
state:存放共享状态;getters:相当于计算属性;mutations:同步修改 state;actions:支持异步逻辑;modules:模块化管理。
📘 Vue3 推荐:
Vue 官方推荐使用 Pinia,API 更简洁、类型友好。
五、通信方式选择建议
| 关系类型 | 推荐通信方式 | 说明 |
|---|---|---|
| 父 → 子 | props | 简单直接 |
| 子 → 父 | $emit | 常用于回调 |
| 父 ↔ 子 | ref | 调用方法或取值 |
| 兄弟组件 | EventBus / mitt | 中央事件总线 |
| 祖孙组件 | provide / inject | 优雅高效 |
| 非关系组件 | Vuex / Pinia | 全局状态共享 |
| 属性透传 | $attrs / $listeners | 批量下传属性 |
| 简单共享状态 | Composition API + reactive() | Vue3 场景 |
六、小结
- 父子通信: 使用
props和$emit最简洁,也可用ref。 - 兄弟通信: 推荐
EventBus或mitt。 - 祖孙通信: 用
provide / inject最优雅。 - 全局通信: 使用
Vuex(Vue2)或Pinia(Vue3)。 - Vue3 提升点: Composition API 让通信更灵活,逻辑更集中。
✅ 总结一句话:
在 Vue 中,组件间通信的本质就是——让数据在不同组件间可控地流动。
本文内容由人工智能生成,仅供学习与参考使用,请在实际应用中结合自身情况进行判断。
《一文读懂 Vue 组件间通信机制(含 Vue2 / Vue3 区别)》 是转载文章,点击查看原文。

