在 Vue 3 中,组合式 API(Composition API)是一个重要的新特性,用于更灵活和高效地组织组件逻辑。下面我们将介绍如何在 Vue 3 中使用组合式 API 实现组件通信。
文章目录
1. 父子组件通信
1.1 父 -> 子通信:props
父组件通过 props
传递数据给子组件,子组件通过 defineProps
函数接收这些数据。
示例:
<!-- 父组件 Parent.vue -->
<template>
<ChildComponent :message="parentMessage" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
const parentMessage = 'Hello from Parent!';
</script>
<!-- 子组件 ChildComponent.vue -->
<template>
<p>{{ message }}</p>
</template>
<script setup>
const props = defineProps({
message: String
});
</script>
在这个例子中,父组件通过 props
向子组件传递了 parentMessage
,子组件通过 defineProps
获取这个数据。
1.2 子 -> 父通信:emit
子组件可以通过 emit
触发事件,父组件通过监听这个事件获取子组件传递的数据。
示例:
<!-- 父组件 Parent.vue -->
<template>
<ChildComponent @customEvent="handleEvent" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
function handleEvent(payload) {
console.log('Received from child:', payload);
}
</script>
<!-- 子组件 ChildComponent.vue -->
<template>
<button @click="sendMessage">Send Message to Parent</button>
</template>
<script setup>
const emit = defineEmits(['customEvent']);
function sendMessage() {
emit('customEvent', 'Hello from Child!');
}
</script>
子组件通过 emit
触发了一个自定义事件 customEvent
,父组件监听这个事件并获取传递的消息。
2. 非父子组件通信
2.1 事件总线(Event Bus)
在 Vue 3 中,由于不能直接使用 Vue 实例作为事件总线,推荐使用 mitt
这个轻量的事件库。
安装 mitt
:
npm install mitt
使用 mitt
实现事件总线通信:
// eventBus.js
import mitt from 'mitt';
export const eventBus = mitt();
示例:
<!-- 组件A ComponentA.vue (发送消息) -->
<template>
<button @click="sendMessage">Send Message to Component B</button>
</template>
<script setup>
import { eventBus } from './eventBus.js';
function sendMessage() {
eventBus.emit('message', 'Hello from Component A!');
}
</script>
<!-- 组件B ComponentB.vue (接收消息) -->
<template>
<p>{{ message }}</p>
</template>
<script setup>
import { eventBus } from './eventBus.js';
import { ref, onMounted, onUnmounted } from 'vue';
const message = ref('');
onMounted(() => {
eventBus.on('message', (msg) => {
message.value = msg;
});
});
onUnmounted(() => {
eventBus.off('message');
});
</script>
组件 A 通过 eventBus.emit
发送消息,组件 B 通过 eventBus.on
接收消息。mitt
提供了简洁的 API 来实现事件的发送与接收。
2.2 使用 Vuex (或 Pinia) 进行全局状态管理
在 Vue 3 中,推荐使用 Pinia 作为状态管理库,取代 Vuex,因为它更加现代和轻量。
安装 Pinia:
npm install pinia
创建 Pinia Store:
// store.js
import { defineStore } from 'pinia';
export const useMainStore = defineStore('main', {
state: () => ({
message: ''
}),
actions: {
updateMessage(newMessage) {
this.message = newMessage;
}
}
});
使用 Store:
<!-- 组件A ComponentA.vue (发送消息) -->
<template>
<button @click="sendMessage">Send Message to Store</button>
</template>
<script setup>
import { useMainStore } from './store.js';
const store = useMainStore();
function sendMessage() {
store.updateMessage('Hello from Component A!');
}
</script>
<!-- 组件B ComponentB.vue (接收消息) -->
<template>
<p>{{ store.message }}</p>
</template>
<script setup>
import { useMainStore } from './store.js';
const store = useMainStore();
</script>
组件 A 通过 store.updateMessage
更新全局状态,组件 B 通过 store.message
响应式地获取全局状态。
3. 跨级组件通信:provide
和 inject
在 Vue 3 中,provide
和 inject
也是通过组合式 API 来实现的,可以用于父级组件向任意深度的子组件提供数据。
示例:
<!-- 父组件 Parent.vue -->
<template>
<ChildComponent />
</template>
<script setup>
import { provide } from 'vue';
const message = 'Hello from Parent';
provide('sharedMessage', message);
</script>
<!-- 子组件 ChildComponent.vue -->
<template>
<p>{{ sharedMessage }}</p>
</template>
<script setup>
import { inject } from 'vue';
const sharedMessage = inject('sharedMessage');
</script>
父组件通过 provide
提供数据,任意深度的子组件通过 inject
获取该数据。
4. 使用 ref
访问子组件实例
父组件可以通过 ref
来直接访问子组件实例中的方法和属性。
示例:
<!-- 父组件 Parent.vue -->
<template>
<ChildComponent ref="childRef" />
<button @click="callChildMethod">Call Child Method</button>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const childRef = ref(null);
function callChildMethod() {
childRef.value.someMethod();
}
</script>
<!-- 子组件 ChildComponent.vue -->
<template>
<p>Child Component</p>
</template>
<script setup>
function someMethod() {
console.log('Child method called!');
}
</script>
父组件通过 ref
获取子组件实例,然后调用子组件中的方法。
5. 透传 attrs
和 listeners
在 Vue 3 中,attrs
和 listeners
的使用被简化,可以通过 useAttrs
来访问所有未声明的 props
,并通过 v-bind
进行透传。
示例:
<!-- 父组件 Parent.vue -->
<template>
<ChildComponent :message="parentMessage" @customEvent="handleEvent" />
</template>
<script setup>
const parentMessage = 'Hello from Parent!';
function handleEvent(data) {
console.log('Received event:', data);
}
</script>
<!-- 子组件 ChildComponent.vue -->
<template>
<GrandChildComponent v-bind="$attrs" />
</template>
<script setup>
import { useAttrs } from 'vue';
const attrs = useAttrs();
</script>
<!-- 孙组件 GrandChildComponent.vue -->
<template>
<p>{{ message }}</p>
<button @click="$emit('customEvent', 'Hello from GrandChild')">Emit Event</button>
</template>
<script setup>
const props = defineProps({
message: String
});
</script>
父组件的 props
和事件通过 $attrs
传递到孙组件,孙组件通过 $emit
触发事件。
总结
在 Vue 3 中使用组合式 API 可以更加灵活地实现组件通信,具体方式包括:
- 父 -> 子通信:通过
props
和defineProps
。 - 子 -> 父通信:通过
$emit
和defineEmits
。 - 跨组件通信:通过事件总线(如
mitt
)或 Pinia(状态管理)。 - 跨级组件通信:使用
provide
和inject
。 - 访问子组件实例:通过
ref
。 - 透传
attrs
和listeners
。
这些方法在组合式 API 的支持下变得更加简洁高效,非常适合在 Vue 3 中使用。