VUE3组件间通信

父子组件:使用 Props/Emits
祖先-后代:使用 Provide/Inject(替代 Vue 2 的 event bus)
复杂应用状态:使用 Pinia(推荐替代 Vuex)
组件间解耦通信:使用 Event Bus(mitt)

1.使用refs获取子组件实例

1.组合式api

父组件

<!-- 父组件 Parent.vue -->
<template>
  <div>
    <Child ref="childRef" />
    <button @click="callChildMethod">调用子组件方法</button>
  </div>
</template>

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

// 1. 创建 ref 引用
const childRef = ref(null)

// 2. 访问子组件实例
const callChildMethod = () => {
  if (childRef.value) {
    childRef.value.increment()
    console.log('子组件 count:', childRef.value.count)
  }
}
</script>

子组件

<!-- 子组件 Child.vue -->
<template>
  <div>子组件</div>
</template>

<script setup>
import { ref } from 'vue'

// 子组件的内部数据和方法
const count = ref(0)

// 子组件的方法
const increment = () => {
  count.value++
}

// 暴露给父组件访问的属性和方法
defineExpose({
  count,
  increment
})
</script>

2.选项式api

和vue2一样的使用this.$refs

2.使用provide、inject进行祖先、后代通信

<!-- 祖先组件 Ancestor.vue -->
<template>
  <div>
    <h2>祖先组件</h2>
    <Parent />
  </div>
</template>

<script setup>
import { provide, ref, reactive } from 'vue'
import Parent from './Parent.vue'

// 1. 提供普通值
const title = ref('应用标题')
provide('appTitle', title)

// 2. 提供响应式对象
const user = reactive({
  name: '张三',
  age: 25
})
provide('user', user)

// 3. 提供方法
const updateUser = (newData) => {
  Object.assign(user, newData)
}
provide('updateUser', updateUser)
</script>


<!-- 后代组件 Descendant.vue -->
<template>
  <div>
    <h3>后代组件</h3>
    <p>标题: {{ appTitle }}</p>
    <p>用户名: {{ user.name }}</p>
  </div>
</template>

<script setup>
import { inject } from 'vue'

// 1. 注入值(没有默认值)
const appTitle = inject('appTitle')

// 2. 注入响应式对象
const user = inject('user')

// 3. 注入方法
const updateUser = inject('updateUser')

// 4. 注入 Symbol key 的值
const theme = inject(ThemeSymbol)

// 5. 注入时提供默认值
const notExists = inject('notExists', '默认值')
</script>

3.v-model进行父子组件通信

<!-- 子组件 MyComponent.vue -->
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
</template>

<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<!-- 父组件使用 -->
<MyComponent v-model="message" />

4.使用事件总线EventBus

// eventBus.js
import mitt from 'mitt'

// 创建事件总线实例
const emitter = mitt()
// 可创建多个不同用途的事件总线
export const globalEmitter = mitt()
export const userEmitter = mitt()
// 默认导出
export default emitter

使用

<!-- 组件 A(发送事件) -->
<template>
  <button @click="sendMessage">发送消息</button>
</template>

<script setup>
import { useEventBus } from './eventBus'

// 发送事件
const sendMessage = () => {
  // 发送简单数据
  useEventBus.emit('message', 'Hello World')
  
  // 发送复杂数据
  useEventBus.emit('user-updated', {
    id: 1,
    name: '张三',
    timestamp: new Date()
  })
  
  // 发送没有数据的事件
  useEventBus.emit('refresh')
}
</script>


<!-- 组件 B(接收事件) -->
<template>
  <div>收到消息: {{ message }}</div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useEventBus } from './eventBus'

const message = ref('')

// 事件处理函数
const handleMessage = (msg) => {
  console.log('收到消息:', msg)
  message.value = msg
}

const handleUserUpdate = (user) => {
  console.log('用户更新:', user)
}

// 组件挂载时监听事件
onMounted(() => {
  useEventBus.on('message', handleMessage)
  useEventBus.on('user-updated', handleUserUpdate)
  useEventBus.on('refresh', () => {
    console.log('刷新事件触发')
  })
  
  // 监听所有事件
  useEventBus.on('*', (type, event) => {
    console.log('所有事件监听:', type, event)
  })
})

// 组件卸载时移除监听
onUnmounted(() => {
  useEventBus.off('message', handleMessage)
  useEventBus.off('user-updated', handleUserUpdate)
  // 移除所有监听器
  // useEventBus.all.clear()
})
</script>
posted @ 2026-01-27 21:09  DurianTRY  阅读(0)  评论(0)    收藏  举报