Vue3 组件通信全攻略:12种方式与实战示例

Vue3 组件通信全攻略:12种方式与实战示例

在Vue3中,组件通信是构建应用的核心技能。本文系统梳理12种通信方式,从基础到进阶,结合真实场景与代码示例,帮助开发者灵活选择最佳方案。


一、父子组件通信

1. Props + Emit(基础单向数据流)

场景 :父组件传递数据给子组件,子组件触发事件通知父组件
示例

javascript 复制代码
// Parent.vue
<template>
  <Child :message="parentMsg" @update="handleUpdate"/>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const parentMsg = ref('Hello from Parent')
const handleUpdate = (newMsg) => {
  parentMsg.value = newMsg
}
</script>

// Child.vue
<template>
  <div>{{ message }} <button @click="sendMessage">Send</button></div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps({
  message: String
})
const emit = defineEmits(['update'])

const sendMessage = () => {
  emit('update', 'Hello from Child')
}
</script>

2. $attrs(透传未声明的属性)

场景 :子组件需要接收父组件传递的非Props属性
示例

javascript 复制代码
// Parent.vue
<template>
  <Child :msg="message" :other="extraData" />
</template>
<script setup>
import Child from './Child.vue'

const message = 'Main Message'
const extraData = { id: 123 }
</script>

// Child.vue
<template>
  <div v-bind="$attrs"></div>
</template>
<script setup>
// $attrs自动包含父组件传递的other属性
</script>

3. Ref + DefineExpose(直接调用子组件方法)

场景 :父组件需要直接调用子组件的方法
示例

javascript 复制代码
// Parent.vue
<template>
  <Child ref="childRef" />
  <button @click="callChildMethod">Call Child</button>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const childRef = ref(null)
const callChildMethod = () => {
  childRef.value.publicMethod()
}
</script>

// Child.vue
<template>
  <div>Child Component</div>
</template>
<script setup>
import { defineExpose } from 'vue'

const publicMethod = () => {
  console.log('Child method called')
}
defineExpose({ publicMethod })
</script>

二、兄弟组件通信

1. Mitt(轻量级事件总线)

场景 :平级组件间需要事件通知
示例

javascript 复制代码
// emitter.js
import mitt from 'mitt'
export const emitter = mitt()

// BrotherA.vue
<script setup>
import { emitter } from './emitter'
emitter.on('notify', (data) => {
  console.log('BrotherA收到消息:', data)
})
</script>

// BrotherB.vue
<script setup>
import { emitter } from './emitter'
setTimeout(() => {
  emitter.emit('notify', { msg: 'Hello BrotherA' })
}, 1000)
</script>

2. 共享父组件状态(通过$parent)

场景 :兄弟组件通过共同的父组件共享数据
示例

javascript 复制代码
// Parent.vue
<template>
  <BrotherA :shared="state" />
  <BrotherB :shared="state" />
</template>
<script setup>
import { reactive } from 'vue'
import BrotherA from './BrotherA.vue'
import BrotherB from './BrotherB.vue'

const state = reactive({ count: 0 })
</script>

// BrotherA.vue
<template>
  <button @click="increment">Increment</button>
</template>
<script setup>
import { defineProps } from 'vue'

const props = defineProps({
  shared: Object
})
function increment() {
  props.shared.count++
}
</script>

三、跨层级组件通信

1. Provide + Inject(祖孙组件数据传递)

场景 :祖先组件向后代组件传递数据,无需逐层传递
示例

javascript 复制代码
// Ancestor.vue
<template>
  <GrandChild />
</template>
<script setup>
import { provide, ref } from 'vue'
import GrandChild from './GrandChild.vue'

const theme = ref('dark')
provide('theme', theme)
</script>

// GrandChild.vue(隔代组件)
<template>
  <div>Theme: {{ theme }}</div>
</template>
<script setup>
import { inject } from 'vue'

const theme = inject('theme')
</script>

四、高级场景通信

1. V-Model 双向绑定(简化父子交互)

场景 :父组件与子组件之间的双向数据同步
示例

javascript 复制代码
// Parent.vue
<template>
  <Child v-model="value" />
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const value = ref('Initial Value')
</script>

// Child.vue
<template>
  <input :value="modelValue" @input="updateValue($event.target.value)" />
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

const updateValue = (val) => {
  emit('update:modelValue', val)
}
</script>

2. 依赖注入(函数/对象传递)

场景 :通过插槽传递函数或配置对象
示例

javascript 复制代码
// Parent.vue
<template>
  <Child>
    <template #default="{ config }">
      <div :style="config">{{ config.title }}</div>
    </template>
  </Child>
</template>
<script setup>
import Child from './Child.vue'
</script>

// Child.vue
<template>
  <div>
    <slot :config="config">
      Default Content
    </slot>
  </div>
</template>
<script setup>
import { reactive } from 'vue'

const config = reactive({ title: 'Slot Injected Config' })
</script>

五、其他补充方案

方式 适用场景 示例代码片段
Vuex/Pinia 全局状态管理 store.commit('increment') / useCounterStore().increment()
LocalStorage 持久化数据共享 localStorage.setItem('key', JSON.stringify(data))
Window全局对象 临时跨组件通信(慎用) window.appData = {...}
ES6 Module Import 常量数据共享 import { CONSTANT } from '@/constants'

六、最佳实践建议

  1. 优先选择标准化方案:Props+Emit满足80%场景,复杂场景再用Provide/Mitt/状态管理
  2. 避免过度使用全局状态:仅当数据需要在多组件间共享时使用Vuex/Pinia
  3. 善用$attrs:减少子组件Props定义,实现属性透传
  4. 谨慎操作Ref:仅在必要时直接调用子组件方法,保持组件解耦
  5. 事件命名规范 :使用on[EventName]监听自定义事件,如on:update

七、扩展学习资源

  • Vue3官方文档 - 组件通信
  • Mitt官方文档
  • Pinia状态管理指南
  • Vue3组合式API详解

通过本文,你可以掌握Vue3组件通信的核心方法,并根据实际场景选择最优方案。建议将示例代码复制到Vue3项目中运行,观察不同方式的数据流向和效果差异。

相关推荐
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端
爱敲代码的小鱼9 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax