【转载】Vue3 组件通信 9 种方式详解
引言
在 Vue3 项目开发中,组件通信是核心基本功。很多同学只会 props/emit,遇到兄弟组件、深层嵌套组件、全局状态交互就无从下手。本文整理 Vue3 所有 9 种组件通信方式,覆盖父子、跨层级、兄弟、全局等所有场景,案例可直接运行代码、适用场景、优缺点、避坑指南,一文彻底吃透 Vue3 组件传值。
Vue3 组件通信总览(9种全覆盖)

父子组件通信(最常用 4 种)
1. defineProps 父传子(单向下传)
场景:父组件向子组件传递展示数据、配置参数
核心规则:单向数据流,子组件禁止直接修改 props
案例:
父组件
<template>
<Child :title="title" :list="list" />
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const title = ref('')
const list = ref([1,2,3])
</script>
子组件:
<script setup>
// 企业级规范:类型+默认值+必填
const props = defineProps({
title: {
type: String,
required: true
},
list: {
type: Array,
default: () => [] // 引用类型必须函数返回
}
})
</script>
2. defineEmits 子传父(事件上报)
场景:子组件点击、输入、操作后,把数据回传给父组件
案例:
子组件
<template>
<button @click="handleSend">回传数据给父组件</button>
</template>
<script setup>
const emit = defineEmits(['onSubmit'])
const handleSend = () => {
emit('onSubmit', '子组件数据', 666)
}
</script>
父组件
<template>
<Child @onSubmit="handleSubmit" />
</template>
<script setup>
const handleSubmit = (str, num) => {
console.log(str, num)
}
</script>
3. v-model 父子双向绑定
场景:弹窗显隐、输入框、数值双向同步
Vue3 支持 多 v-model,告别 .sync 修饰符
案例:
父组件
<template>
<Child v-model:visible="dialogVisible" v-model:count="num" />
</template>
<script setup>
import { ref } from 'vue'
const dialogVisible = ref(false)
const num = ref(0)
</script>
子组件
<script setup>
const props = defineProps(['visible', 'count'])
const emit = defineEmits(['update:visible', 'update:count'])
const closeDialog = () => {
emit('update:visible', false)
}
const addCount = () => {
emit('update:count', props.count + 1)
}
</script>
4. ref + defineExpose 父调用子方法/取值
场景:父组件主动调用子组件的方法、获取子组件内部数据
setup 默认关闭实例暴露,必须手动 defineExpose
案例:
子组件
<script setup>
import { ref } from 'vue'
const msg = ref('子组件内部数据')
const childFn = () => {
console.log('子组件方法被调用')
}
// 暴露给父组件
defineExpose({
msg,
childFn
})
</script>
父组件
<template>
<Child ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'
const childRef = ref(null)
onMounted(() => {
// 调用子组件方法、取值
childRef.value.childFn()
console.log(childRef.value.msg)
})
</script>
跨层级组件通信(2种)
1. $attrs 自动属性透传
场景:多层嵌套组件,父组件参数无需逐层手动传递
特点:自动透传所有非 props 属性、事件、class、style
案例
父组件(最外层)
<GrandChild title="标题透传" :time="time" />
深层子组件(直接接收)
<template>
<div>{{ $attrs.title }} {{ $attrs.time }}</div>
</template>
2. provide / inject 祖先向后代全局注入
场景:主题色、全局配置、用户信息、权限、多层嵌套通用数据 学习计算机课
优势:无视层级,任意后代组件均可取值,支持响应式
案例:
祖先组件(提供数据)
<script setup>
import { ref, provide } from 'vue'
const theme = ref('dark')
const userInfo = ref({ name: 'admin', role: 'admin' })
// 注入全局数据
provide('theme', theme)
provide('user', userInfo)
</script>
任意后代组件(接收数据)
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
const user = inject('user')
</script>
注意:传入 ref/reactive 可保持响应式,普通变量无响应式
兄弟组件 / 任意组件通信(2种)
1. Mitt 轻量事件总线(简单场景首选)
场景:兄弟组件、无关联组件简单消息通知、数据交互 学习计算机课
Vue3 移除了原生 bus,推荐使用 mitt
案例:
安装 & 封装 bus.js
npm install mitt
// src/utils/bus.js
import mitt from 'mitt'
export const emitter = mitt()
组件A(发送方)
<script setup>
import { emitter } from '@/utils/bus'
// 触发事件
emitter.emit('refreshList', '我是A组件数据')
</script>
组件B(接收方)
<script setup>
import { emitter } from '@/utils/bus'
import { onMounted, onUnmounted } from 'vue'
// 监听事件
onMounted(() => {
emitter.on('refreshList', (data) => {
console.log('接收数据:', data)
})
})
// 销毁监听(防内存泄漏)
onUnmounted(() => {
emitter.off('refreshList')
})
</script>
2. Pinia 全局状态管理(复杂项目首选)
场景:全局共享数据、复杂状态、多组件频繁读写、持久化数据
Vue3 官方替代 Vuex ,极简、轻量化、类型友好
案例
定义 store
// src/stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
userName: '',
token: ''
}),
actions: {
setUser(name) {
this.userName = name
}
}
})
任意组件使用
<script setup>
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
// 改数据
userStore.setUser('前端开发者')
// 取数据
console.log(userStore.userName)
</script>
极简方案:父组件中转(兄弟通信)
场景:临时少量兄弟交互,不想装插件 、不写状态管理
- 兄弟A 通过 emit 把数据传给父组件
- 父组件接收数据、更新自身状态
- 父组件通过 props 传给兄弟B
缺点:多层嵌套会产生 props 层层穿透,复杂项目不推荐
各通信方式最佳场景选型(实战必看)
- 普通父子传值:props / emit / v-model
- 父调用子方法:ref + defineExpose
- 深层嵌套传全局配置:provide / inject
- 多层属性透传:$attrs
- 简单兄弟/跨组件通知:mitt 事件总线
- 全局共享、复杂状态:Pinia
高频避坑总结
- 禁止直接修改 props:破坏单向数据流,Vue3 直接报错 学习计算机课
- mitt 必须手动销毁监听,否则造成内存泄漏
- provide 普通变量无响应式,必须传 ref/reactive
- setup 组件默认不暴露实例,必须 defineExpose 父组件才能调用
- 复杂业务坚决用 Pinia,少用 bus 和多层 props 穿透
总结
Vue3 的 9 种组件通信方式覆盖了所有业务场景:简单父子交互用基础API、跨层用 provide/inject、兄弟简单通信用 mitt、全局状态统一用 Pinia。
转载地址:https://blog.csdn.net/kiritomzzz/article/details/162766682
作者:bingbing-blog
出处:http://www.cnblogs.com/bingbing-blog/
本文版权归作者和博客园共有,转载必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。

浙公网安备 33010602011771号