Vue3 组件通信有哪些方式?

1. Props / Emits(父子)

<!-- Parent -->
<template>
  <Child :message="msg" @update="handleUpdate" />
</template>

<!-- Child -->
<script setup>
const props = defineProps(['message'])
const emit = defineEmits(['update'])

emit('update', newValue)
</script>

2. v-model(双向绑定)

<!-- Vue3 支持多个 v-model -->
<Child v-model:title="title" v-model:content="content" />

<!-- Child -->
<script setup>
const props = defineProps(['title', 'content'])
const emit = defineEmits(['update:title', 'update:content'])
</script>

3. provide / inject(跨层级)

// 祖先组件
import { provide, ref } from 'vue'

const theme = ref('dark')
provide('theme', theme)  // 提供响应式数据

// 任意后代组件
import { inject } from 'vue'
const theme = inject('theme')  // 接收

// 带默认值
const config = inject('config', { default: true })

// 只读
import { readonly } from 'vue'
provide('theme', readonly(theme))

4. ref(父调子方法)

<!-- Parent -->
<template>
  <Child ref="childRef" />
  <button @click="childRef.focus()">Focus</button>
</template>

<!-- Child -->
<script setup>
import { ref } from 'vue'
const inputRef = ref(null)

// 暴露方法给父组件
defineExpose({
  focus: () => inputRef.value?.focus(),
  clear: () => { /* ... */ }
})
</script>

5. mitt(事件总线)

// eventBus.js
import mitt from 'mitt'
export const bus = mitt()

// 组件 A
bus.emit('custom-event', data)

// 组件 B
import { onMounted, onUnmounted } from 'vue'
onMounted(() => bus.on('custom-event', handler))
onUnmounted(() => bus.off('custom-event', handler))

6. Pinia(全局状态管理)

// store/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', () => {
  const name = ref('')
  const setName = (n) => name.value = n
  return { name, setName }
})

// 任何组件
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
userStore.setName('Tom')

对比

方式 场景 复杂度
Props/Emits 父子 低
v-model 父子双向 低
provide/inject 跨层级 中
ref + defineExpose 父调子 中
mitt 任意组件 低
Pinia 全局状态 中

Vue3 变化

同分类其他题目