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

相关推荐
举个栗子dhy14 小时前
第四章、路由配置
前端·javascript·react.js
XiaoYu200214 小时前
AI精准提问手册:从模糊需求到精准输出的核心技能(上)
前端·人工智能·程序员
windliang14 小时前
前端 AI 自动化测试:brower-use 调研
前端·agent·测试
小高00714 小时前
instanceof 和 typeof 的区别:什么时候该用哪个?
前端·javascript·面试
im_AMBER14 小时前
React 03
前端·笔记·学习·react.js·前端框架·react
over69714 小时前
从代码到歌词:我用AI为汪峰创作了一首情歌
前端
老前端的功夫14 小时前
JavaScript的`this`指向:送你一张永远不会错的地图
前端
前端没钱14 小时前
Tauri2+vue3+NaiveUI仿写windows微信,安装包仅为2.5M,95%的API用JavaScript写,太香了
前端·vue.js·rust
用户2794282861314 小时前
HTML5 敲击乐:从零搭建交互式前端音乐项目
前端