一、父子组件通信
1. Props + Events(最基础)
-
适用场景:父子组件直接传递数据(父传子用
props
,子传父用emit
)。 -
优点:符合单向数据流,逻辑清晰。
-
示例:
vue
<!-- 父组件 --> <Child :value="parentData" @update="handleUpdate" /> <!-- 子组件 --> <script setup> const props = defineProps(['value']); const emit = defineEmits(['update']); emit('update', newValue); </script>
2. v-model(语法糖)
-
适用场景:简化表单类组件的双向绑定。
-
原理:
v-model
是:modelValue
+@update:modelValue
的语法糖。 -
示例:
vue
<!-- 父组件 --> <Child v-model="data" /> <!-- 子组件 --> <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
二、跨层级组件通信
1. Provide/Inject
-
适用场景:祖先组件向后代组件传递数据(无需逐层传递)。
-
优点:适合全局配置(如主题、用户信息)、深层嵌套组件。
-
示例:
vue
<!-- 祖先组件 --> <script setup> import { provide } from 'vue'; provide('theme', 'dark'); </script> <!-- 后代组件 --> <script setup> import { inject } from 'vue'; const theme = inject('theme', 'light'); // 默认值 'light' </script>
2. 状态管理(Pinia/Vuex)
-
适用场景:复杂应用的多组件共享状态(如用户登录态、购物车)。
-
优点:集中管理状态,支持响应式、调试工具。
-
推荐:Vue 3 首选 Pinia(更简洁,替代 Vuex)。
-
示例:
js
// store/counter.js export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++ } } }); // 组件中使用 const counter = useCounterStore(); counter.increment();
三、兄弟组件/无直接关系组件
1. 状态管理(Pinia/Vuex)
-
适用场景:兄弟组件共享数据或跨组件通信。
-
优点:解耦组件,状态可追踪。
2. 事件总线(谨慎使用)
-
适用场景:小型项目快速实现通信(Vue 3 需借助第三方库如
mitt
)。 -
缺点:事件流难追踪,大型项目慎用。
-
示例:
js
// eventBus.js import mitt from 'mitt'; export const emitter = mitt(); // 组件 A 发送事件 emitter.emit('event-name', data); // 组件 B 监听事件 emitter.on('event-name', (data) => { ... });
四、直接操作组件
1. 模板引用(Template Refs)
-
适用场景:父组件直接调用子组件方法或访问 DOM。
-
示例:
vue
<!-- 父组件 --> <Child ref="childRef" /> <script setup> import { ref } from 'vue'; const childRef = ref(null); childRef.value.someMethod(); </script> <!-- 子组件 --> <script setup> defineExpose({ someMethod: () => { ... } }); </script>
选择策略总结
场景 | 推荐方式 |
---|---|
父子组件 | props + emit 、v-model |
深层嵌套组件 | provide /inject |
兄弟/无关系组件 | Pinia(状态管理) |
全局共享状态 | Pinia(如用户信息、主题) |
简单快速通信 | 事件总线(小型项目) |
直接操作子组件 | 模板引用(ref + defineExpose ) |
注意事项
-
避免过度使用事件总线:易导致代码混乱,优先考虑状态管理。
-
保持单向数据流:子组件不要直接修改
props
,应通过事件通知父组件。 -
合理分层:简单场景用
props/emit
,复杂场景用状态管理。
根据项目规模和组件关系选择最简洁的方案,避免过度设计!