Skip to content

组件通信

字数: 0 字 时长: 0 分钟

简介

组件通信是 Vue 开发中绕不开的话题,也是面试高频考点。这篇笔记整理了 Vue3 中常用的几种组件通信方式:props/emits、v-model、provide/inject、mitt 事件总线和 Pinia 状态管理。

父子通信:props / emits

父组件通过 props 向子组件传递数据,子组件通过 emits 向父组件触发事件。

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

const msg = ref("来自父组件的消息");

const handleChange = (val) => {
  console.log("子组件说:", val);
};
</script>

<template>
  <Child :msg="msg" @change="handleChange" />
</template>
vue
<script setup>
// 接收 props
const props = defineProps({
  msg: String,
});

// 声明 emits
const emit = defineEmits(["change"]);

const send = () => {
  emit("change", "我收到啦");
};
</script>

<template>
  <div>{{ props.msg }}</div>
  <button @click="send">回复父组件</button>
</template>

双向绑定:v-model

v-model 本质是 :modelValue + @update:modelValue 的语法糖,Vue3 支持多个 v-model

vue
<template>
  <!-- 父组件 -->
  <Child v-model:title="title" v-model:content="content" />
</template>
vue
<script setup>
// 子组件
const props = defineProps(["title", "content"]);
const emit = defineEmits(["update:title", "update:content"]);

emit("update:title", "新标题");
</script>

跨层级通信:provide / inject

祖先组件通过 provide 提供数据,后代组件通过 inject 注入使用,适合隔代传值。

js
import { provide, ref } from "vue";

const theme = ref("dark");
provide("theme", theme); // 提供响应式数据
js
import { inject } from "vue";

const theme = inject("theme"); // 注入使用

注意

provide 提供的数据默认是只读约定,建议在提供方暴露修改方法,避免后代组件直接改动导致数据流向混乱。

任意组件通信:mitt 事件总线

Vue3 移除了 $on$off,官方推荐使用 mitt 实现事件总线。

bash
pnpm add mitt
js
import mitt from "mitt";
export const bus = mitt();
js
import { bus } from "./bus";
bus.emit("sayHello", "你好呀");
js
import { onUnmounted } from "vue";
import { bus } from "./bus";

const handler = (msg) => console.log(msg);
bus.on("sayHello", handler);

// 组件卸载时记得移除监听
onUnmounted(() => bus.off("sayHello", handler));

全局状态管理:Pinia

跨组件共享复杂状态时,直接用 Pinia,它是 Vue 官方推荐的状态管理库,替代了 Vuex。

js
import { defineStore } from "pinia";

export const useUserStore = defineStore("user", {
  state: () => ({ name: "卡比", age: 18 }),
  getters: {
    info: (state) => `${state.name},${state.age} 岁`,
  },
  actions: {
    growUp() {
      this.age++;
    },
  },
});
vue
<script setup>
import { useUserStore } from "./stores/user";

const user = useUserStore();
user.growUp(); // 调用 action
</script>

<template>
  <div>{{ user.info }}</div>
</template>

通信方式选择

场景推荐方式
父传子props
子传父emits / v-model
跨层级(隔代)provide / inject
任意组件简单通信mitt
全局共享状态Pinia
最后更新于: 2026/8/5 15:00:00