Vue3 | 组件通信学习小结

今天集中学习并复习了 Vue3 中核心的组件通信方式,整理了 Props/Emits、Provide/Inject、Mitt 事件总线三种常用方式的代码实践和核心要点,方便后续复习回顾,也希望帮到正在学习Vue3的你们~

一、 Prop + Emits 基础父子 / 跨级组件通信

这是 Vue 中最基础的组件通信方式,适用于父子组件,也可通过中间组件转发实现跨级(父→子→孙 / 孙→子→父)通信。(关于Props和Emits详情部分可观看前几篇文章)

核心原理

  • Props:父组件向子组件传递数据(只读),支持类型校验。
  • Emits:子组件向父组件触发自定义事件并传递数据,可声明事件类型。

代码示例(跨级通信)

1. 祖先组件
TypeScript 复制代码
<script setup lang="ts">
import { ref } from "vue";
import middle from "./study_tree/15.组件通信/17_1.middle.vue"

// 接收子组件传递的参数
function claim(name:string){
  alert(name)
}

const name = ref("") // 响应式数据
</script>

<template>
  <div>
    App
    <!-- 父组件向中间组件传值 + 监听事件 -->
    <middle name="L" @submit="claim"></middle>
    {{ name }}   
  </div>
</template>
2. 中间组件
TypeScript 复制代码
<script setup lang="ts">
import Sub from "./17_2.sub1.vue"

// 定义Props类型
interface p {
    name:string
}
// 接收父组件传递的Props
const props = defineProps<p>()
// 声明要触发的事件
const emit = defineEmits(['submit'])

// 转发子组件的事件到父组件
function up(name:string){
    emit("submit",name)
}
</script>

<template>
  <div>
    中间组件
    <!-- 向孙组件传值 + 监听孙组件事件 -->
    <Sub :name="props.name" @submit="up"></Sub>
  </div>
</template>
3. 孙组件
TypeScript 复制代码
<script setup lang="ts">
// 定义Props类型
interface p {
    name:string
}
// 接收中间组件传递的Props
const props = defineProps<p>()
// 声明要触发的事件
const emit = defineEmits(['submit'])

// 触发事件,向父组件(中间组件)传值
function up(name:string){
    emit("submit",name)
}
</script>

<template>
  <div>
    孙子组件
    name:{{props.name}}
    <!-- 点击触发事件,传递参数 -->
    <button @click="up('张三')">点击</button>
  </div>
</template>

核心要点

  • Props 是单向数据流,子组件不能直接修改,需通过 Emits 通知父组件修改。
  • 跨级通信时,中间组件需要做 "转发":接收上层的 Props 传递给下层,监听下层的 Emits 再触发给上层。
  • 可通过接口(interface)约束 Props 类型,提升代码健壮性。

二、Provide + Inject:跨层级全局共享数据

当组件层级较深时(如父→子→孙→重孙),Props/Emits 转发会很繁琐,Provide/Inject 可实现 "祖先组件提供数据,任意后代组件注入使用",无视层级限制。

核心原理

  • Provide :祖先组件通过 **provide**暴露数据 / 方法,可传递普通值或响应式数据(ref/reactive)。
  • Inject :后代组件通过 **inject**接收祖先提供的数据,直接使用。

代码示例

1. 祖先组件提供数据
TypeScript 复制代码
<script setup lang="ts">
import { provide, ref } from "vue";
import middle from "./study_tree/15.组件通信/17_1.middle.vue"

// 提供普通数据(非响应式)
provide("msg","L")// 键值 键msg 值"L"

// 提供响应式数据(ref包裹)
const name = ref("")
provide("name",name)
</script>
2. 孙组件注入使用
XML 复制代码
<script setup lang="ts">
import { inject } from 'vue';

// 注入祖先提供的普通数据
const msg = inject("msg")
// 注入祖先提供的响应式数据
const name = inject("name")
</script>

<template>
  <div>
    孙子组件
    <!-- 使用非响应式数据 -->
    通过provide-inject传递: {{msg}}
    <br>
    <!-- 使用响应式数据(支持v-model双向绑定) -->
    通过inject拿到的响应式数据
    <input type="text" v-model="name">
    {{ name }}
  </div>
</template>

核心要点

  • 默认情况下 Provide 传递的普通数据是非响应式的,需用 ref/reactive 包裹才能保持响应式。
  • Inject 可设置默认值:inject("key", "默认值"),避免数据不存在时报错。
  • 适合全局共享的通用数据(如用户信息、主题配置),但过度使用会降低组件独立性。

三、Mitt 事件总线:任意组件通信

Vue3 移除了内置的 EventBus,可通过第三方库 **mitt**实现任意组件(无层级限制)的通信,适用于非父子组件、跨层级组件的通信场景。

核心原理

  • 安装 mitt : npm install mitt 。
  • 创建全局事件总线实例,通过 emit 触发事件、 on 监听事件、 off 取消监听。

代码示例

1. 创建全局总线
TypeScript 复制代码
import mitt from "mitt";
const bus = mitt();
export default bus
2. 组件A监听/触发事件
TypeScript 复制代码
<script setup lang="ts">
import bus from "./until/bus";

// 监听自定义事件 "sun"
bus.on("sun",(data:string)=>{
  console.log("App接收到的消息:", data);
})

// 触发自定义事件 "sum"
function sendMsg(){
  bus.emit("sum","总结")
}
</script>

<template>
  <button @click="sendMsg">通过mitt发送消息到sub</button>
</template>
3. 组件B监听/触发事件
TypeScript 复制代码
<script setup lang="ts">
import bus from '@/until/bus';

// 触发自定义事件 "sun"
function sendMsg(){
    bus.emit("sun","内容")
}

// 监听自定义事件 "sum"
bus.on("sum",(data:string)=>{
    console.log("Sub接收到的消息:", data);
})
</script>

<template>
  <button @click="sendMsg">通过mitt发送消息到app</button>
</template>

核心要点

  • 注意清理事件监听:在组件卸载时( onUnmounted )执行 bus.off("事件名", 回调) ,避免内存泄漏。
  • 适合小型项目的非父子组件通信

四、三种通信方式对比

三种方式各有优缺,寻找合适场景使用

表格

方式 适用场景 特点
Props +Emits 父子/跨级通信(层级跨度不高) 基础、单向数据流
Provide + inject 跨层级全局共享(层级跨度高) 无视层级、可响应式
Mitt事件总线 任意组件通信(非父子/跨层级) 灵活、无层级限制

五、小结

  • 优先使用 Props + Emits 处理父子组件通信,符合 Vue 单向数据流设计理念。
  • 跨层级全局共享数据用 Provide + Inject,记得用 ref/reactive 保持响应式。
  • 非父子 / 跨层级临时通信可用 Mitt,大型项目建议结合状态管理库(Pinia)。
  • 组件通信的核心是 "数据流向清晰",避免滥用全局通信方式导致代码难以维护。

欢迎各位补充说明~

相关推荐
C澒2 小时前
IntelliPro 企业级产研协作平台:前端智能生产模块设计与落地
前端·ai编程
OpenTiny社区3 小时前
重磅预告|OpenTiny 亮相 QCon 北京,共话生成式 UI 最新技术思考
前端·开源·ai编程
前端老实人灬3 小时前
web前端面试题
前端
Moment3 小时前
AI 全栈指南:NestJs 中的 Service Provider 和 Module
前端·后端·面试
IT_陈寒3 小时前
为什么我的JavaScript异步回调总是乱序执行?
前端·人工智能·后端
Moment3 小时前
AI全栈入门指南:NestJs 中的 DTO 和数据校验
前端·后端·面试
小码哥_常3 小时前
告别RecyclerView卡顿!8个优化技巧让列表丝滑如德芙
前端
小村儿4 小时前
Harness Engineering:为什么你用 AI 越用越累?
前端·后端·ai编程
enoughisenough4 小时前
浏览器判断控制台是否开启
前端