Vue3 组件通信方式全景梳理与选型建议

发布于2026-08-15 11:52 阅读10次 系统梳理 Vue3 中所有组件通信方式:props/emit、provide/inject、defineExpose、Pinia 状态管理、事件总线等,分析各自适用场景和避坑点,帮助开发者根据场景选择最合适的通信方案。
# Vue3 组件通信方式全景梳理与选型建议
## 前言
组件通信是 Vue 开发的基本功,但很多开发者对不同方式的使用场景把握不准,导致代码里 props 满天飞、provide 滥用。本文系统梳理 Vue3 的组件通信方式,给出选型建议。
## 一、父传子:props
最基础的方式,单向数据流。
```javascript
// 父组件
<ChildComponent :title="title" :count="count" />
// 子组件
const props = defineProps({
title: { type: String, required: true },
count: { type: Number, default: 0 },
});
```
注意:不要直接修改 props,如果需要改变,应该用 emit 通知父组件改。
## 二、子传父:emit
```javascript
// 子组件
const emit = defineEmits(["update", "delete"]);
emit("update", newValue);
// 父组件
<ChildComponent @update="handleUpdate" />
```
### v-model 语法糖
```javascript
// 子组件用 defineModel (Vue 3.4+)
const model = defineModel();
model.value = newVal; // 自动 emit update:modelValue
// 父组件直接 v-model
<ChildComponent v-model="inputValue" />
```
## 三、跨层级:provide/inject
祖孙组件通信,避免层层透传 props。
```javascript
// 祖先组件
provide("theme", "dark");
provide("userInfo", readonly(userInfo)); // 传只读
// 后代组件
const theme = inject("theme");
const userInfo = inject("userInfo");
```
避坑:provide 的对象最好用 readonly 包裹,防止后代随意修改。
## 四、父访问子:defineExpose
```javascript
// 子组件暴露方法
defineExpose({
reset() {
form.value = initialForm;
},
});
// 父组件用 ref 调用
const childRef = ref();
childRef.value.reset();
```
注意:setup 默认是关闭的,必须显式 defineExpose 才能访问。
## 五、全局状态:Pinia
跨组件共享复杂状态的首选。
```javascript
// stores/cart.ts
export const useCartStore = defineStore("cart", () => {
const items = ref([]);
const total = computed(() => items.value.reduce((s, i) => s + i.price, 0));
function addItem(item) { items.value.push(item); }
return { items, total, addItem };
});
```
适用:登录态、购物车、主题、全局配置等需要多处读写的状态。
## 六、事件总线(不推荐)
Vue3 移除了实例上的 $on/$emit,官方不推荐事件总线。如需跨组件事件,用 mitt 库:
```javascript
import mitt from "mitt";
const emitter = mitt();
// 发送
emitter.emit("logout");
// 接收
emitter.on("logout", () => {});
```
但更建议优先用 Pinia 替代事件总线,状态可追踪、易维护。
## 选型决策表
| 场景 | 推荐方式 |
|------|---------|
| 父传子静态数据 | props |
| 子通知父 | emit / defineModel |
| 祖孙跨层级传值 | provide/inject |
| 父调用子方法 | defineExpose |
| 全局共享状态 | Pinia |
| 兄弟组件通信 | Pinia 或共同父组件 |
## 小结
选型原则:能用 props/emit 解决的就不上全局状态;跨层级用 provide/inject;复杂共享状态交给 Pinia;尽量避免事件总线。清晰的通信方式能让代码可维护性大幅提升。