Skip to content

在 Vue 项目中,组件通信是开发过程中非常常见的需求,尤其是在父子组件和兄弟组件之间。Vue 提供了多种方式来实现不同层级的组件之间的通信。以下是几种常见的父子组件和兄弟组件通信方式:

一、父子组件通信

父子组件通信是最基础的通信方式,Vue 通过 props$emit 来实现父组件与子组件之间的数据传递。

1. props 向子组件传递数据

父组件通过 props 向子组件传递数据,这是单向数据流的一部分,父组件将数据传递给子组件,但子组件不能直接修改 props

示例:父组件通过 props 向子组件传递数据

vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  data() {
    return {
      parentMessage: 'Hello from Parent'
    };
  },
  components: {
    ChildComponent
  }
};
</script>

<!-- ChildComponent.vue -->
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: ['message']  // 接收父组件传递的 message
};
</script>

在这个示例中,parentMessage 通过 props 传递到子组件 ChildComponent,子组件通过 props 显示父组件传递的数据。

2. $emit 向父组件传递数据

子组件不能直接修改父组件传递的 props,但是可以通过 $emit 触发事件,通知父组件数据的变化。

示例:子组件通过 $emit 触发事件,向父组件传递数据

vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent @update-message="updateMessage" />
    <p>Message from Child: {{ childMessage }}</p>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  data() {
    return {
      childMessage: ''
    };
  },
  methods: {
    updateMessage(newMessage) {
      this.childMessage = newMessage;
    }
  },
  components: {
    ChildComponent
  }
};
</script>

<!-- ChildComponent.vue -->
<template>
  <div>
    <button @click="sendMessage">Send Message to Parent</button>
  </div>
</template>

<script>
export default {
  methods: {
    sendMessage() {
      this.$emit('update-message', 'Hello from Child');
    }
  }
};
</script>

在这个示例中,子组件 ChildComponent 通过 $emit 向父组件触发 update-message 事件,父组件捕获该事件并执行 updateMessage 方法来更新 childMessage


二、兄弟组件通信

兄弟组件之间没有直接的父子关系,因此不能直接通过 props$emit 进行通信。Vue 提供了多种方式来实现兄弟组件之间的通信:

1. 通过父组件作为中介

父组件可以作为中介,通过父组件来协调兄弟组件之间的通信。兄弟组件 A 向父组件发送事件,父组件再将数据传递给兄弟组件 B。

示例:通过父组件中介实现兄弟组件通信

vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <ComponentA @send-data="receiveData" />
    <ComponentB :receivedData="dataFromA" />
  </div>
</template>

<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';

export default {
  data() {
    return {
      dataFromA: ''
    };
  },
  methods: {
    receiveData(data) {
      this.dataFromA = data;
    }
  },
  components: {
    ComponentA,
    ComponentB
  }
};
</script>

<!-- ComponentA.vue -->
<template>
  <div>
    <button @click="sendDataToParent">Send Data to Component B</button>
  </div>
</template>

<script>
export default {
  methods: {
    sendDataToParent() {
      this.$emit('send-data', 'Hello from Component A');
    }
  }
};
</script>

<!-- ComponentB.vue -->
<template>
  <div>
    <p>Received Data: {{ receivedData }}</p>
  </div>
</template>

<script>
export default {
  props: ['receivedData']  // 接收从父组件传递过来的数据
};
</script>

在这个示例中,ComponentA 向父组件发送数据,父组件通过 props 将数据传递给 ComponentB,从而实现兄弟组件之间的通信。

2. 使用事件总线(Event Bus)

事件总线是一种非官方的通信方式,可以通过一个中央事件总线对象在兄弟组件之间传递消息。虽然 Vue 3 中不再推荐使用事件总线,但它仍然可以用来在某些简单的场景中实现兄弟组件通信。

示例:使用事件总线实现兄弟组件通信

javascript
// EventBus.js
import Vue from 'vue';
export const EventBus = new Vue();
vue
<!-- ComponentA.vue -->
<template>
  <div>
    <button @click="sendData">Send Data to Component B</button>
  </div>
</template>

<script>
import { EventBus } from './EventBus';

export default {
  methods: {
    sendData() {
      EventBus.$emit('data-sent', 'Hello from Component A');
    }
  }
};
</script>

<!-- ComponentB.vue -->
<template>
  <div>
    <p>{{ receivedData }}</p>
  </div>
</template>

<script>
import { EventBus } from './EventBus';

export default {
  data() {
    return {
      receivedData: ''
    };
  },
  mounted() {
    EventBus.$on('data-sent', (data) => {
      this.receivedData = data;
    });
  }
};
</script>

在这个示例中,EventBus 作为事件总线在 ComponentAComponentB 之间传递数据。ComponentA 通过 EventBus.$emit 发送数据,ComponentB 通过 EventBus.$on 监听数据变化。

3. 使用 Vuex 实现全局状态管理

在复杂的应用中,尤其是涉及到多个组件通信时,Vue 官方推荐使用 Vuex 来管理全局状态。Vuex 是一个专门为 Vue 应用设计的状态管理模式,它可以通过共享的状态让兄弟组件方便地通信。

示例:使用 Vuex 实现兄弟组件通信

  1. 安装 Vuex

    bash
    npm install vuex
  2. 创建 Vuex Store

    javascript
    // store.js
    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: {
        sharedData: ''
      },
      mutations: {
        setData(state, data) {
          state.sharedData = data;
        }
      }
    });
  3. 在兄弟组件中使用 Vuex

    vue
    <!-- ComponentA.vue -->
    <template>
      <div>
        <button @click="sendData">Send Data to Component B</button>
      </div>
    </template>
    
    <script>
    import { mapMutations } from 'vuex';
    
    export default {
      methods: {
        ...mapMutations(['setData']),
        sendData() {
          this.setData('Hello from Component A');
        }
      }
    };
    </script>
    
    <!-- ComponentB.vue -->
    <template>
      <div>
        <p>Data from A: {{ sharedData }}</p>
      </div>
    </template>
    
    <script>
    import { mapState } from 'vuex';
    
    export default {
      computed: {
        ...mapState(['sharedData'])
      }
    };
    </script>

在这个示例中,ComponentA 通过调用 Vuex 的 mutation 修改全局状态,ComponentB 通过计算属性监听全局状态的变化,从而实现兄弟组件之间的通信。


总结

  1. 父子组件通信

    • 父组件通过 props 向子组件传递数据。
    • 子组件通过 $emit 触发事件向父组件传递数据。
  2. 兄弟组件通信

    • 通过父组件作为中介:兄弟组件通过父组件转发数据。
    • 使用事件总线(Event Bus):简单场景下可以通过事件总线在兄弟组件之间通信,但 Vue 3 不推荐使用。
    • 使用 Vuex:在复杂场景下,使用 Vuex 来管理全局状态,实现任意组件间的通信。

对于小型应用,使用 props$emit 来处理父