Vue3组件通信全方案

Vue3 组件通信全方案(10种写法+详细实例)

Vue3 组件通信分父子、兄弟、跨级/全局 三大场景,我把所有常用+官方推荐的写法整理好了,带完整可运行代码,直接复制就能用。

一、父子组件通信(最常用 6 种)

1. props / emit(标准写法:父传子 + 子传父)

适用场景:父 ↔ 子 双向通信(Vue 最基础、最推荐)

父组件 Parent.vue
vue 复制代码
<template>
  <div>
    <h2>父组件</h2>
    <!-- 父传子:msg -->
    <!-- 子传父:@sendMsg 监听子组件事件 -->
    <Child :msg="parentMsg" @sendMsg="getChildMsg" />
    <p>子组件传来的消息:{{ childMsg }}</p>
  </div>
</template>

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

// 父传给子的数据
const parentMsg = ref('我是父组件的消息')
// 接收子组件的数据
const childMsg = ref('')

// 监听子组件触发的事件
const getChildMsg = (val) => {
  childMsg.value = val
}
</script>
子组件 Child.vue
vue 复制代码
<template>
  <div>
    <h3>子组件</h3>
    <p>父组件传来的消息:{{ msg }}</p>
    <button @click="toParent">点击给父组件传值</button>
  </div>
</template>

<script setup>
// 1. 接收父组件传值:props
const props = defineProps({
  msg: {
    type: String,
    default: ''
  }
})

// 2. 向父组件传值:emit
const emit = defineEmits(['sendMsg'])

const toParent = () => {
  // 触发事件,把值传给父组件
  emit('sendMsg', '我是子组件的消息')
}
</script>

2. v-model(双向绑定,语法糖)

适用场景:表单、弹窗显隐、需要双向同步的数据

父组件
vue 复制代码
<template>
  <Child v-model="value" />
</template>

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const value = ref('')
</script>
子组件
vue 复制代码
<template>
  <input 
    :value="modelValue" 
    @input="emit('update:modelValue', $event.target.value)"
  />
</template>

<script setup>
// v-model 默认参数:modelValue
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

自定义 v-model 名称(多个双向绑定):

vue 复制代码
<!-- 父 -->
<Child v-model:name="name" v-model:age="age" />

<!-- 子 -->
defineProps(['name', 'age'])
defineEmits(['update:name', 'update:age'])

3. ref / $parent(父直接获取子实例)

适用场景 :父组件直接调用子组件方法 / 数据

父组件
vue 复制代码
<template>
  <Child ref="childRef" />
  <button @click="getChild">调用子组件方法</button>
</template>

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

// 获取子组件实例
const childRef = ref(null)

const getChild = () => {
  // 调用子组件方法
  childRef.value.sayHello()
  // 获取子组件数据
  console.log(childRef.value.childMsg)
}
</script>
子组件
vue 复制代码
<script setup>
import { ref } from 'vue'

const childMsg = ref('我是子组件数据')

// 方法必须暴露,父组件才能访问
const sayHello = () => {
  alert('子组件方法被调用了')
}

// 关键:暴露属性/方法给父组件
defineExpose({
  childMsg,
  sayHello
})
</script>

4. provide / inject(跨层级父子:爷 → 孙)

适用场景:父/爷组件 → 深层子组件传值(跨级)

顶层组件(爷/父)
vue 复制代码
<script setup>
import { provide, ref } from 'vue'

const msg = ref('我是顶层组件数据')

// 提供数据
provide('globalMsg', msg)
</script>
深层子组件(孙/曾孙)
vue 复制代码
<script setup>
import { inject } from 'vue'

// 注入数据
const msg = inject('globalMsg')
console.log(msg) // 顶层组件数据
</script>

✅ 响应式传递 :provide 传递 ref/reactive 对象,子孙修改会同步更新。


5. 插槽传值(子 → 父:作用域插槽)

适用场景 :子组件把数据传给父组件的插槽内容

子组件 Child.vue
vue 复制代码
<template>
  <div>
    <!-- 子组件把数据传给插槽 -->
    <slot :childData="childData" />
  </div>
</template>

<script setup>
import { ref } from 'vue'
const childData = ref('子组件插槽数据')
</script>
父组件
vue 复制代码
<template>
  <Child>
    <!-- 接收子组件插槽数据 -->
    <template v-slot="slotProps">
      {{ slotProps.childData }}
    </template>
  </Child>
</template>

6. $attrs(透传属性,爷 → 孙)

适用场景:中间组件不处理,直接把属性/事件传给子组件

父组件
vue 复制代码
<Child title="我是标题" @click="handleClick" />
中间组件(Middle.vue)
vue 复制代码
<template>
  <!-- 所有属性/事件直接透传给孙组件 -->
  <GrandChild v-bind="$attrs" />
</template>

<script setup>
import GrandChild from './GrandChild.vue'
</script>
孙组件
vue 复制代码
<script setup>
// 接收透传的属性
const props = defineProps(['title'])
</script>

二、兄弟组件通信(2 种)

1. 父组件中转(最简单)

思路:兄 → 父 → 弟

vue 复制代码
<!-- 父组件作为中转站 -->
<BrotherA @send="val => brotherMsg = val" />
<BrotherB :msg="brotherMsg" />

2. mitt(事件总线,Vue3 官方推荐)

Vue3 移除了 $bus,用 mitt 代替全局事件通信

1)安装 mitt
bash 复制代码
npm install mitt
2)创建工具文件 eventBus.js
js 复制代码
import mitt from 'mitt'
export default mitt()
3)兄弟A(发送方)
vue 复制代码
<script setup>
import bus from './eventBus.js'

// 发送事件
const send = () => {
  bus.emit('toBrother', '我是兄弟A的数据')
}
</script>
4)兄弟B(接收方)
vue 复制代码
<script setup>
import bus from './eventBus.js'
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  // 监听事件
  bus.on('toBrother', (val) => {
    console.log(val)
  })
})

// 组件销毁时移除监听
onUnmounted(() => {
  bus.off('toBrother')
})
</script>

三、全局/跨页面通信(2 种)

1. Pinia(Vue 官方状态管理,首选)

适用场景:全局共享数据(用户信息、主题、购物车)

1)安装
bash 复制代码
npm install pinia
2)创建 store
js 复制代码
// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    name: '张三'
  }),
  actions: {
    setName(name) {
      this.name = name
    }
  }
})
3)任意组件使用
vue 复制代码
<script setup>
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()

// 获取数据
console.log(userStore.name)

// 修改数据
userStore.setName('李四')
</script>

2. localStorage / sessionStorage

适用场景:页面刷新后仍需要保留的数据

js 复制代码
// 存
localStorage.setItem('msg', '全局数据')

// 取
localStorage.getItem('msg')

// 删
localStorage.removeItem('msg')

快速选型指南(直接背)

通信场景 推荐方案 优先级
父 ↔ 子 props / emit 1
父子双向绑定 v-model 2
父调用子方法 ref + defineExpose 3
跨级父子 provide / inject 4
兄弟组件 mitt / 父中转 5
全局共享 Pinia 1
页面刷新保留 localStorage -

总结

  1. 父子通信 :优先 props/emitv-model;跨级用 provide/inject
  2. 兄弟通信 :简单用父中转,复杂用 mitt
  3. 全局通信 :必须用 Pinia(Vue3 官方标准)
  4. 所有代码都是 Vue3 + script setup 最新语法,可直接在项目中运行
相关推荐
前端那点事1 小时前
双Token无感刷新:Vue3 + Axios 企业级完整实现
前端·vue.js
前端那点事1 小时前
Vue Token鉴权避坑指南|5步完整实现(从生成到失效全解析)
前端·vue.js
Momo__1 小时前
package.json 配置详解:依赖管理深度指南
前端
漫游的渔夫1 小时前
前端开发者做 Agent:模型说执行就执行?先加 3 道闸门再碰真实业务
前端·人工智能·typescript
前端那点事1 小时前
企业级Vue前端鉴权方案全解析|从Token到OAuth2.0,覆盖多端适配+权限管控
前端·vue.js
亲亲小宝宝鸭1 小时前
从Vben-Admin里面学习hooks
前端·vue.js
Mintopia1 小时前
MSW Mock Feature-First 方案
前端·架构
sin6032 小时前
Talk is cheap 之后:AI Agent 时代,程序员真正要交付什么?
前端
Ticnix2 小时前
手把手教你在 Next.js 中接入本地大模型,实现 ChatGPT 同款流式对话
前端·next.js