vue3组件通信

在 Vue 3 中,父子组件之间的通信方式非常丰富,可以根据组件的关系、数据流方向、复杂程度来选择。下面我帮你整理成一个 清晰体系 ,包括 优缺点、使用场景、示例


🧩 一、Props + Event(最常用、单向数据流)

1️⃣ 父组件 → 子组件:props

  • 父组件通过 props 向子组件传递数据
  • 数据是响应式的,子组件可读不可直接修改父组件的值(可通过 v-model 或自定义事件来实现双向绑定)
js 复制代码
<!-- Parent.vue -->
<template>
  <Child :msg="message" @change="handleChange" />
</template>

<script>
import Child from './Child.vue'
import { ref } from 'vue'

export default {
  components: { Child },
  setup() {
    const message = ref('Hello Vue 3')
    const handleChange = (val) => { console.log('子组件通知:', val) }
    return { message, handleChange }
  }
}
</script>
js 复制代码
<!-- Child.vue -->
<template>
  <button @click="$emit('change', '子组件事件')">{{ msg }}</button>
</template>

<script>
export default {
  props: ['msg']
}
</script>

2️⃣ 子组件 → 父组件:emit

  • 子组件通过 $emit 发事件通知父组件
  • 常用于按钮点击、数据修改、事件触发等

🧩 二、v-model 双向绑定(语法糖)

  • Vue 3 支持在子组件上自定义 v-model 的 prop 名和事件名
  • 常用于表单组件或数据需要双向绑定的场景
js 复制代码
<!-- Parent.vue -->
<template>
  <Child v-model:count="count" />
  <p>{{ count }}</p>
</template>

<script>
import { ref } from 'vue'
import Child from './Child.vue'
export default { components: { Child }, setup() { const count = ref(0); return { count } } }
</script>

<!-- Child.vue -->
<template>
  <button @click="$emit('update:count', count+1)">+1</button>
</template>
<script>
import { ref } from 'vue'
export default {
  props: { count: Number },
  setup(props) { return { count: props.count } }
}
</script>

🧩 三、Provide / Inject(跨级组件传递)

  • 父组件使用 provide 提供数据
  • 子组件及深层组件使用 inject 注入数据
  • 用于多级组件通信、避免层层传递 props
js 复制代码
<!-- GrandParent.vue -->
<script setup>
import { provide } from 'vue'
const theme = 'dark'
provide('theme', theme)
</script>

<!-- Child.vue -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
console.log(theme) // 'dark'
</script>

⚠️ 注意:Provide / Inject 不是响应式的,如果需要响应式,提供的是 refreactive


🧩 四、通过 ref 获取子组件实例

  • 父组件通过 ref 获取子组件实例,调用子组件的方法
  • 常用于非数据通信,比如调用子组件的内部方法、重置表单、播放视频等
js 复制代码
<!-- Parent.vue -->
<template>
  <Child ref="childRef" />
  <button @click="callChild">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childRef = ref(null)
const callChild = () => { childRef.value.sayHello() }
</script>

<!-- Child.vue -->
<script setup>
const sayHello = () => { console.log('Hello from child') }
</script>

🧩 五、全局状态管理(Vuex / Pinia / reactive store)

  • 父子组件通过共享 全局 store 实现通信
  • 适合跨组件、跨页面共享状态
  • Vue 3 推荐 Pinia 作为轻量化状态管理
js 复制代码
// store.js
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
  state: () => ({ count: 0 }),
  actions: { increment() { this.count++ } }
})

// Parent.vue / Child.vue
import { useStore } from './store'
const store = useStore()
store.increment() // 任意组件都可以修改

🧩 六、Event Bus(自定义事件总线)

  • Vue 3 不再内置 EventBus,但可以用 mitt 创建事件总线
  • 常用于兄弟组件通信,或者父子组件通信也可
  • 不推荐大量使用,容易造成维护困难
js 复制代码
// bus.js
import mitt from 'mitt'
export const bus = mitt()

// Parent.vue
import { bus } from './bus.js'
bus.on('myEvent', val => console.log(val))

// Child.vue
import { bus } from './bus.js'
bus.emit('myEvent', 'hello bus')

🧠 总结

通信方式 方向 场景 备注
Props + emit 父 → 子 / 子 → 父 常规父子通信 最推荐
v-model 父 ↔ 子 表单 / 双向绑定 Vue 3 支持自定义 prop 名
provide / inject 父 → 多级子 跨级传值 避免层层传递 props
ref 调用子组件方法 父 → 子 调用方法 非数据通信
Pinia / Vuex 全局 跨组件 / 跨页面 状态管理必备
Event Bus (mitt) 全局 / 任意方向 兄弟组件 / 临时通信 不推荐大量使用

总结一句话:

一般情况用 Props + emit / v-model;跨级用 provide/inject;跨组件用 Pinia;调用方法用 ref;EventBus 仅作补充。

相关推荐
卓怡学长16 分钟前
m111基于MVC的舞蹈网站的设计与实现
java·前端·数据库·spring boot·spring·mvc
C_心欲无痕5 小时前
前端实现水印的两种方式:SVG 与 Canvas
前端·安全·水印
尾善爱看海8 小时前
不常用的浏览器 API —— Web Speech
前端
美酒没故事°9 小时前
vue3拖拽+粘贴的综合上传器
前端·javascript·typescript
jingling55510 小时前
css进阶 | 实现罐子中的水流搅拌效果
前端·css
悟能不能悟11 小时前
前端上载文件时,上载多个文件,但是一个一个调用接口,怎么实现
前端
可问春风_ren12 小时前
前端文件上传详细解析
前端·ecmascript·reactjs·js
羊小猪~~13 小时前
【QT】--文件操作
前端·数据库·c++·后端·qt·qt6.3
晚风资源组13 小时前
CSS文字和图片在容器内垂直居中的简单方法
前端·css·css3
Miketutu14 小时前
Flutter学习 - 组件通信与网络请求Dio
开发语言·前端·javascript