兄弟组件通信方案详解
方案一:通过父组件中转
这是最直接的方式,适用于兄弟组件有共同父组件且嵌套层级不深的场景。
- 原理 :
- 子组件 A 通过
$emit触发自定义事件,将数据传递给父组件。 - 父组件监听该事件,接收数据并更新自身状态(如
data)。 - 父组件通过
props将数据传递给子组件 B。
- 子组件 A 通过
- 示例代码:
vue
<!-- ParentComponent.vue -->
<template>
<div>
<ChildA @data-from-A="handleDataFromA" />
<ChildB :message="messageForB" />
</div>
</template>
<script>
export default {
data() {
return {
messageForB: ""
};
},
methods: {
handleDataFromA(data) {
this.messageForB = data; // 父组件接收数据并更新
}
}
};
</script>
<!-- ChildA.vue -->
<template>
<button @click="sendData">传递数据</button>
</template>
<script>
export default {
methods: {
sendData() {
this.$emit("data-from-A", "来自A的数据"); // 触发事件并传递数据
}
}
};
</script>
<!-- ChildB.vue -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ["message"] // 通过props接收父组件传递的数据
};
</script>
方案二:使用事件总线(Event Bus)
适用于组件层级较深或跨层级通信的场景,避免逐层传递的繁琐。
- 原理 :
- 创建全局事件总线(一个空的 Vue 实例)。
- 子组件 A 通过
eventBus.$emit()触发事件并传递数据。 - 子组件 B 通过
eventBus.$on()监听事件并接收数据。
- 示例代码:
js
// event-bus.js
import Vue from "vue";
export const eventBus = new Vue();
vue
<!-- ChildA.vue -->
<template>
<button @click="sendData">通过总线传递</button>
</template>
<script>
import { eventBus } from "./event-bus";
export default {
methods: {
sendData() {
eventBus.$emit("data-event", "总线数据"); // 触发全局事件
}
}
};
</script>
<!-- ChildB.vue -->
<template>
<div>{{ busMessage }}</div>
</template>
<script>
import { eventBus } from "./event-bus";
export default {
data() {
return {
busMessage: ""
};
},
mounted() {
eventBus.$on("data-event", data => {
this.busMessage = data; // 监听事件并更新数据
});
},
beforeDestroy() {
eventBus.$off("data-event"); // 组件销毁时移除监听
}
};
</script>
方案三:使用 Vuex
适用于中大型项目,需要集中管理多个组件共享状态的场景。
- 原理 :
- 定义全局状态(如
store.state.message)。 - 子组件 A 通过
this.$store.commit()提交mutation修改状态。 - 子组件 B 通过
this.$store.state.message或计算属性获取状态。
- 定义全局状态(如
- 简要实现:
js
// store.js
import Vuex from "vuex";
export default new Vuex.Store({
state: {
message: ""
},
mutations: {
setMessage(state, payload) {
state.message = payload; // 修改状态
}
}
});
vue
<!-- ChildA.vue -->
<script>
export default {
methods: {
sendData() {
this.$store.commit("setMessage", "Vuex数据"); // 提交mutation
}
}
};
</script>
<!-- ChildB.vue -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
computed: {
message() {
return this.$store.state.message; // 获取状态
}
}
};
</script>
总结与选择建议
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 父组件中转 | 简单场景,组件层级浅 | 无需额外工具,逻辑清晰 | 嵌套深时传递繁琐 |
| 事件总线(Event Bus) | 跨层级通信,小型项目 | 解耦组件,灵活 | 事件名需全局管理,易内存泄漏 |
| Vuex | 中大型项目,状态共享频繁 | 集中管理状态,可追踪变化 | 学习成本高,略重 |
实际选择:
- 简单功能(如按钮触发更新)优先用 方案一。
- 跨组件/非父子通信用 方案二,注意及时销毁事件监听。
- 复杂状态逻辑(如用户登录信息共享)用 方案三。