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(事件总线)
import mitt from 'mitt'
export const bus = mitt()
bus.emit('custom-event', data)
import { onMounted, onUnmounted } from 'vue'
onMounted(() => bus.on('custom-event', handler))
onUnmounted(() => bus.off('custom-event', handler))
6. Pinia(全局状态管理)
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 变化
- 移除了
$children(改用 ref)
- 移除了
$on / $off / $once(实例不再实现事件接口)
defineExpose 替代 Vue2 的直接访问子组件方法
同分类其他题目