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 仅作补充。

相关推荐
教练、我想打篮球12 小时前
123 safari 浏览器中下载 URLEncoder.encode 的中文名称的文件, safari 未进行解码, 其他浏览器正常
前端·http·safari
小白x12 小时前
Echarts常用配置
前端
hello_Code12 小时前
css和图片主题色“提取”
前端
小杨梅君12 小时前
Vue3与iframe通信方案详解:本地与跨域场景
前端·vue.js
IT_陈寒12 小时前
Redis高频踩坑实录:5个不报错但会导致性能腰斩的'隐秘'配置项
前端·人工智能·后端
CoolerWu12 小时前
2025 · 我与 AI / Vibe Coding 的一年
前端·后端
张风捷特烈12 小时前
AI 四格笑话爆火,我做了什么?
前端·aigc
东方-教育技术博主12 小时前
IDEA 配置electron开发环境
前端·javascript·electron
AC赳赳老秦12 小时前
DeepSeek-Coder vs Copilot:嵌入式开发场景适配性对比实战
java·前端·后端·struts·mongodb·copilot·deepseek
一只专注api接口开发的技术猿12 小时前
智能决策数据源:利用 1688 商品详情 API 构建实时比价与供应链分析系统
大数据·前端·数据库