在 Vue 中,兄弟组件(同一层级的组件)之间没有直接的通信方式,需要通过“中间介质”来实现间接通信。常用的方案有以下几种,适用于不同场景:
1. 父组件中转(最常用)
通过父组件作为中间桥梁,实现兄弟组件间的通信:
- 步骤:
- 兄弟 A 向父组件发送数据(
$emit) - 父组件接收后,通过 props 传递给兄弟 B
- 兄弟 A 向父组件发送数据(
- 示例:
<!-- 父组件 Parent.vue -->
<template>
<div>
<!-- 兄弟A:发送数据给父组件 -->
<BrotherA @sendData="handleDataFromA" />
<!-- 兄弟B:通过props接收父组件的数据 -->
<BrotherB :dataFromA="dataFromA" />
</div>
</template>
<script>
import BrotherA from './BrotherA.vue'
import BrotherB from './BrotherB.vue'
export default {
components: { BrotherA, BrotherB },
data() {
return {
dataFromA: null // 存储从A组件接收的数据
}
},
methods: {
handleDataFromA(data) {
// 接收A的数据,准备传递给B
this.dataFromA = data
}
}
}
</script>
<!-- 兄弟A组件 BrotherA.vue -->
<template>
<button @click="sendToB">发送数据给B</button>
</template>
<script>
export default {
methods: {
sendToB() {
// 向父组件发送数据
this.$emit('sendData', '来自A的数据')
}
}
}
</script>
<!-- 兄弟B组件 BrotherB.vue -->
<template>
<p>从A接收的数据:{
{ dataFromA }}</p>
</template>
<script>
export default {
props: ['dataFromA'] // 接收父组件传递的A的数据
}
</script>
2. 事件总线(EventBus)
创建一个全局事件中心,兄弟组件通过它发送和接收事件:
- 步骤:
- 创建全局事件总线实例
- 组件 A 通过
$emit发送事件 - 组件 B 通过
$on监听事件
- 示例:
// 1. 创建事件总线(main.js)
import Vue from 'vue'
Vue.prototype.$bus = new Vue() // 挂载到Vue原型上
<!-- 兄弟A组件 -->
<template>
<button @click="sendToB">发送数据给B</button>
</template>
<script>
export default {
methods: {
sendToB() {
// 发送事件到总线
this.$bus.$emit('brother-event', '来自A的数据')
}
}
}
</script>
<!-- 兄弟B组件 -->
<template>
<p>从A接收的数据:{
{ message }}</p>
</template>
<script>
export default {
data() {
return { message: null }
},
mounted() {
// 监听总线事件
this.$bus.$on('brother-event', (data) => {
this.message = data
})
},
beforeDestroy() {
// 移除监听,避免内存泄漏
this.$bus.$off('brother-event')
}
}
</script>
3. Vuex / Pinia(全局状态管理)
适合大型项目中多个兄弟组件共享状态:
- 步骤:
- 在 Store 中定义共享状态
- 组件 A 提交 mutation/action 修改状态
- 组件 B 通过 getter 或直接访问状态获取数据
- Pinia 示例:
// store.js(定义共享状态)
import {
defineStore } from 'pinia'
export const useBrotherStore = defineStore('brother', {
state: () => ({
sharedData: null }),
actions: {
updateSharedData(data) {
this.sharedData = data
}
}
})
<!-- 兄弟A组件 -->
<template>
<button @click="sendToB">发送数据给B</button>
</template>
<script>
import { useBrotherStore } from './store'
export default {
methods: {
sendToB() {
const store = useBrotherStore()
// 修改全局状态
store.updateSharedData('来自A的数据')
}
}
}
</script>
<!-- 兄弟B组件 -->
<template>
<p>从A接收的数据:{
{ store.sharedData }}</p>
</template>
<script>
import { useBrotherStore } from './store'
export default {
setup() {
const store = useBrotherStore()
return { store }
}
}
</script>
4. provide / inject(跨层级透传)
如果兄弟组件有共同的祖先,可以通过祖先组件的 provide 提供数据,兄弟组件都用 inject 获取:
- 示例:
<!-- 共同祖先组件 -->
<script>
export default {
provide() {
return {
brotherData: this.brotherData,
setBrotherData: this.setBrotherData
}
},
data() { return { brotherData: null } },
methods: {
setBrotherData(data) {
this.brotherData = data
}
}
}
</script>
<!-- 兄弟A组件 -->
<script>
export default {
inject: ['setBrotherData'],
methods: {
sendToB() {
this.setBrotherData('来自A的数据') // 调用祖先方法修改数据
}
}
}
</script>
<!-- 兄弟B组件 -->
<script>
export default {
inject: ['brotherData'],
// 可以通过watch监听数据变化
watch: {
brotherData(newVal) {
console.log('从A接收的数据:', newVal)
}
}
}
</script>
选择建议
- 小型项目/简单场景:优先用 父组件中转 或 事件总线
- 大型项目/复杂状态:推荐用 Vuex/Pinia(可追踪状态变化,适合团队协作)
- 有共同祖先的兄弟组件:可考虑 provide/inject
实际开发中,父组件中转和状态管理方案最常用,事件总线需注意及时移除监听以避免内存泄漏。