Skip to content

组件通信

Vue 3 提供了多种组件通信方式,包括 父子通信、兄弟通信、跨层级通信、全局状态管理 等。下面详细介绍 Vue 3 的 常见组件通信方式 及其适用场景。


1. 父子组件通信

父子组件的通信方式主要有:

  • props(父传子)
  • $emit(子传父)
  • v-model(双向绑定)

(1) props(父传子)

适用于:父组件向子组件传递数据。

📌 示例

vue
<!-- 父组件 -->
<template>
  <ChildComponent :message="msg" />
</template>

<script setup>
import ChildComponent from "./ChildComponent.vue";
import { ref } from "vue";

const msg = ref("Hello from Parent");
</script>
vue
<!-- 子组件 -->
<template>
  <p>父组件数据: {{ message }}</p>
</template>

<script setup>
defineProps(["message"]); // Vue 3 使用 defineProps 代替 Vue 2 的 props
</script>

📌 父组件通过 props 向子组件传递 message,子组件通过 defineProps() 接收数据


(2) $emit(子传父)

适用于:子组件向父组件传递事件或数据。

📌 示例

vue
<!-- 父组件 -->
<template>
  <ChildComponent @send-message="handleMessage" />
</template>

<script setup>
import ChildComponent from "./ChildComponent.vue";

const handleMessage = (msg) => {
  console.log("收到子组件数据:", msg);
};
</script>
vue
<!-- 子组件 -->
<template>
  <button @click="sendMessage">发送数据</button>
</template>

<script setup>
import { defineEmits } from "vue";

const emit = defineEmits(["send-message"]);

const sendMessage = () => {
  emit("send-message", "Hello from Child");
};
</script>

📌 子组件 emit("send-message") 触发事件,父组件监听并接收数据


(3) v-model(双向绑定)

适用于:父子组件双向数据绑定。

📌 示例

vue
<!-- 父组件 -->
<template>
  <ChildComponent v-model="msg" />
</template>

<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

const msg = ref("Hello Vue 3");
</script>
vue
<!-- 子组件 -->
<template>
  <input v-model="message" />
</template>

<script setup>
import { defineProps, defineEmits, computed } from "vue";

const props = defineProps(["modelValue"]);
const emit = defineEmits(["update:modelValue"]);

const message = computed({
  get: () => props.modelValue,
  set: (val) => emit("update:modelValue", val),
});
</script>

📌 Vue 3 v-model 默认使用 modelValue,子组件通过 emit("update:modelValue") 触发更新


2. 兄弟组件通信

Vue 3 没有 this.$bus,可以使用:

  • mitt 事件总线
  • ref() / reactive() 作为共享状态

(1) mitt 事件总线

适用于:兄弟组件之间的事件触发。

📌 安装 mitt

sh
npm install mitt

📌 创建事件总线

js
// eventBus.js
import mitt from "mitt";
export const EventBus = mitt();

**📌 组件 A(发送数据)

vue
<template>
  <button @click="sendData">发送数据</button>
</template>

<script setup>
import { EventBus } from "@/eventBus";

const sendData = () => {
  EventBus.emit("custom-event", "Hello from Component A");
};
</script>

📌 组件 B(接收数据)

vue
<template>
  <p>收到数据: {{ message }}</p>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import { EventBus } from "@/eventBus";

const message = ref("");

onMounted(() => {
  EventBus.on("custom-event", (data) => {
    message.value = data;
  });
});

onUnmounted(() => {
  EventBus.off("custom-event");
});
</script>

📌 mitt 实现事件总线,兄弟组件可以跨层级通信


(2) ref() / reactive() 作为共享状态

适用于:简单状态共享。

📌 共享状态

js
// store.js
import { reactive } from "vue";

export const globalState = reactive({
  message: "Hello Vue 3"
});

📌 组件 A(修改数据)

vue
<template>
  <button @click="changeMessage">修改数据</button>
</template>

<script setup>
import { globalState } from "@/store";

const changeMessage = () => {
  globalState.message = "Updated by Component A";
};
</script>

📌 组件 B(读取数据)

vue
<template>
  <p>全局数据: {{ globalState.message }}</p>
</template>

<script setup>
import { globalState } from "@/store";
</script>

📌 使用 reactive() 让多个组件共享状态,避免 props 层层传递


3. 跨组件/全局通信

对于深层嵌套组件或跨页面状态管理,可以使用:

  • provide/inject(祖孙通信)
  • Pinia(全局状态管理)

(1) provide/inject(祖孙组件通信)

适用于:跨层级组件数据传递。

📌 父组件(提供数据)

vue
<template>
  <ChildComponent />
</template>

<script setup>
import { provide, ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

const message = ref("Hello from Parent");
provide("globalMessage", message);
</script>

📌 子组件(接收数据)**

vue
<template>
  <p>父组件提供的数据: {{ globalMessage }}</p>
</template>

<script setup>
import { inject } from "vue";

const globalMessage = inject("globalMessage");
</script>

📌 provide() 在祖组件提供数据,inject() 在后代组件中接收数据


(2) Pinia(全局状态管理)

适用于:复杂状态管理、多个页面共享状态。

📌 安装 Pinia

sh
npm install pinia

📌 创建全局状态

js
// store.js
import { defineStore } from "pinia";

export const useMainStore = defineStore("main", {
  state: () => ({
    message: "Hello Pinia"
  }),
  actions: {
    setMessage(newMsg) {
      this.message = newMsg;
    }
  }
});

📌 组件 A(修改状态)

vue
<template>
  <button @click="updateMessage">修改状态</button>
</template>

<script setup>
import { useMainStore } from "@/store";

const store = useMainStore();

const updateMessage = () => {
  store.setMessage("Updated by Component A");
};
</script>

📌 组件 B(读取状态)

vue
<template>
  <p>全局数据: {{ store.message }}</p>
</template>

<script setup>
import { useMainStore } from "@/store";

const store = useMainStore();
</script>

📌 Pinia 适合全局状态管理,支持 setup()Options API


4. 组件通信方式对比

方式适用场景Vue 3 API
props / $emit父子组件通信defineProps / defineEmits
v-model父子双向绑定v-model
mitt兄弟组件通信mitt.emit() / mitt.on()
reactive()共享状态reactive() / ref()
provide/inject祖孙组件通信provide() / inject()
Pinia全局状态管理defineStore()

🚀 Vue 3 推荐 Pinia 进行全局状态管理,mitt 适合轻量级事件通信!

评论区

欢迎留言、补充或勘误。

xiaoba.blog