以下是对 Vue 组件通信的完整技术解析,包含 8 种主要方式及其核心实现原理:
---
### 一、父子组件通信
#### 1. Props / $emit(基础通信)
**实现原理**:通过虚拟 DOM 的 props 属性传递数据,利用 Vue 的事件系统触发自定义事件
```vue
<!-- 父组件 -->
<ChildComponent :msg="parentMsg" @update="handleUpdate"/>
<!-- 子组件 -->
<script setup>
const props = defineProps(['msg'])
const emit = defineEmits(['update'])
function sendData() {
emit('update', newValue)
}
</script>
```
**特性**:单向数据流,适用于直接父子关系
---
#### 2. v-model(双向绑定)
**实现原理**:语法糖实现 props + 事件监听
```vue
<CustomInput v-model="searchText" />
<!-- 等价于 -->
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
```
**特性**:Vue3 支持多个 v-model 绑定
---
### 二、跨级组件通信
#### 3. Provide / Inject(依赖注入)
**实现原理**:通过组件树层级上下文传递数据
```javascript
// 祖先组件
import { provide, ref } from 'vue'
const count = ref(0)
provide('counter', count)
// 后代组件
import { inject } from 'vue'
const counter = inject('counter')
```
**注意点**:默认非响应式,需配合 `ref`/`reactive` 使用
---
#### 4. $attrs(透传属性)
**实现原理**:自动继承未被 props 声明的属性
```vue
<!-- 中间组件 -->
<Grandchild v-bind="$attrs" />
<!-- 最终组件 -->
<script setup>
defineProps(['deepProp'])
</script>
```
**Vue3 变化**:包含除 `class`/`style` 外的所有属性
---
### 三、兄弟组件通信
#### 5. 事件总线(Event Bus)
**实现原理**:创建独立 Vue 实例作为事件中心
```javascript
// eventBus.js
import { createApp } from 'vue'
export const bus = createApp({})
// 组件A
bus.config.globalProperties.$emit('event', data)
// 组件B
bus.config.globalProperties.$on('event', callback)
```
**注意**:Vue3 推荐改用 `mitt` 等第三方库
---
### 四、全局状态管理
#### 6. Vuex/Pinia(状态管理)
**核心流程**:
```
组件 → dispatch Action → commit Mutation → 修改 State → 触发响应式更新
```
**Pinia 优势**:
- 取消 `mutations` 简化流程
- 完整 TypeScript 支持
- 组合式 API 风格
---
### 五、特殊场景方案
#### 7. 作用域插槽
**实现原理**:通过插槽 prop 反向传递数据
```vue
<!-- 父组件 -->
<template #default="slotProps">
{{ slotProps.childData }}
</template>
<!-- 子组件 -->
<slot :childData="dataToPass" />
```
#### 8. 模板引用(Ref)
**实现原理**:直接访问组件实例
```vue
<ChildComponent ref="childRef" />
<script setup>
import { ref } from 'vue'
const childRef = ref(null)
// 访问 childRef.value.methodName()
</script>
```
---
### 技术选型建议
1. **简单父子**:props/emit(数据流清晰)
2. **深层嵌套**:provide/inject(避免逐层传递)
3. **兄弟组件**:事件总线/Pinia(根据复杂度选择)
4. **大型项目**:Pinia + 类型系统(维护性最佳)
5. **UI组件库**:组合使用 $attrs + 插槽(灵活扩展)
**性能注意**:频繁通信场景建议使用 Vuex/Pinia,避免大量自定义事件导致的性能损耗
---
通过合理选择通信方式,可以构建出高内聚低耦合的组件架构。建议在开发前期规划好数据流方案,避免后期出现「属性钻孔」(prop drilling)等问题。