一次搞清Vue3中组件通讯的全部方式
作者:鱼樱前端
Vue 3 提供了多种组件间通信的方法,每种方法适用于不同的场景
1. 父组件向子组件传递数据 (Props)
父组件可以通过 props 将数据传递给子组件。
示例:
// 父组件
<template>
<ChildComponent :message="parentMessage" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
const parentMessage = 'Hello from Parent';
</script>
// 子组件
<template>
<div>{{ message }}</div>
</template>
<script setup>
defineProps(['message']);
</script>
2. 子组件向父组件传递数据 ($emit)
子组件可以使用 $emit 触发事件,父组件监听这些事件来接收数据。
示例:
// 父组件
<template>
<ChildComponent @update-message="updateMessage" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
function updateMessage(newMessage) {
console.log(newMessage);
}
</script>
// 子组件
<template>
<button @click="sendUpdate">Send Update</button>
</template>
<script setup>
import { defineEmits } from 'vue';
const emit = defineEmits(['update-message']);
function sendUpdate() {
emit('update-message', 'Hello from Child');
}
</script>
3. 兄弟组件通信 (通过共同父组件或Vuex)
如果组件没有直接的父子关系,可以通过共同的父组件作为中介或者使用 Vuex 进行状态管理。
示例 (通过共同父组件):
// 父组件
<template>
<SiblingA @share-data="handleShareData" />
<SiblingB :sharedData="sharedData" />
</template>
<script setup>
import SiblingA from './SiblingA.vue';
import SiblingB from './SiblingB.vue';
const sharedData = ref(null);
function handleShareData(data) {
sharedData.value = data;
}
</script>
4. 使用 provide/inject
provide 和 inject 可以用来跨越多个组件层级进行数据传递。
示例:
// 父组件
<template>
<ChildComponent />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
provide('parentMessage', 'Hello from Parent');
</script>
// 子组件
<template>
<div>{{ message }}</div>
</template>
<script setup>
import { inject } from 'vue';
const message = inject('parentMessage');
</script>
5. 使用 Vuex 或 Pinia
对于更复杂的应用程序,通常会使用 Vuex 或 Pinia 进行状态管理。
示例 (Vuex):
// Vuex Store
// store.js
import { createStore } from 'vuex';
export default createStore({
state: {
counter: 0,
},
mutations: {
increment(state) {
state.counter++;
},
},
});
// 组件中使用 Vuex
<template>
<div>
<p>计数器: {{ counter }}</p>
<button @click="increment">增加</button>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';
const store = useStore();
// 使用计算属性获取状态
const counter = computed(() => store.state.counter);
// 定义方法以提交mutation
const increment = () => {
store.commit('increment');
};
</script>
6. 使用事件总线 (Event Bus)
虽然官方文档不推荐这种方式,但在某些情况下,创建一个事件总线可以帮助非父子组件间通信。
示例:
import { createApp } from 'vue';
const eventBus = createApp({}).config.globalProperties.$bus;
eventBus.$on('some-event', (data) => {
// 处理事件
});
7. 使用 Refs
在 Vue 3 中,你可以使用 ref 属性来访问子组件实例,并调用其方法或属性。
示例:
// 父组件
<template>
<ChildComponent ref="childRef" />
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const childRef = ref();
function callChildMethod() {
childRef.value.childMethod();
}
</script>
8. 使用 mitt
mitt 是一个轻量级的事件总线库,可以在 Vue 3 应用中用于实现组件间的通信。
# 使用 pnpm 推荐 pnpm add mitt # 使用 npm npm install mitt # 使用 yarn yarn add mitt
初始化 mitt
接下来,在项目的某个共享位置初始化 mitt 实例。通常,你可以将它放在一个单独的文件中,比如 src/utils/eventBus.js:
// src/utils/eventBus.js import mitt from 'mitt' // 创建一个事件总线实例 const emitter = mitt() export default emitter
使用 mitt 在组件之间发送事件
现在,你可以在任何需要的地方导入并使用这个事件总线实例。下面是一个简单的例子,展示如何在一个组件中发送事件,并在另一个组件中监听事件:
发送事件的组件 (SenderComponent.vue)
<template>
<button @click="sendMessage">Send Message</button>
</template>
<script setup>
import eventBus from '@/utils/eventBus'
function sendMessage() {
eventBus.emit('messageSent', 'Hello from Sender')
}
</script>
监听事件的组件 (ReceiverComponent.vue)
<template>
<div>{{ lastMessage }}</div>
</template>
<script setup>
import eventBus from '@/utils/eventBus'
const lastMessage = ref('')
// 监听事件
eventBus.on('messageSent', (message) => {
lastMessage.value = message
})
// 清理函数,确保卸载时移除事件监听器
onBeforeUnmount(() => {
eventBus.off('messageSent')
})
</script>
9. 使用 pinia
Pinia 是一个非常强大的状态管理库,类似于 Vuex,但更加简洁和灵活。通过 Pinia,我们可以轻松地实现组件间的通信。Pinia 的状态管理机制使得数据的存储和更新变得非常简单,同时提供了很好的灵活性和可维护性。这种方法非常适合大型应用,尤其是当组件间的数据流比较复杂时
安装 Pinia
首先,你需要安装 Pinia。如果你还没有安装,可以通过 npm 或 yarn 来安装:
# 使用 pnpm 推荐 pnpm add pinia # 使用 npm npm install pinia # 使用 yarn yarn add pinia
初始化 Pinia
接下来,在项目的某个共享位置初始化 Pinia 实例。通常,你可以将它放在一个单独的文件中,比如 src/stores/index.js:
// src/stores/index.js
import { defineStore } from 'pinia'
// 定义一个 store
export const useMainStore = defineStore('main', {
state: () => ({
message: 'Hello from Pinia'
}),
actions: {
updateMessage(newMessage) {
this.message = newMessage
}
}
})
配置 Pinia
在主应用文件中配置 Pinia,并将其注入到 Vue 应用中:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
import { useMainStore } from './stores/index'
const app = createApp(App)
// 创建 Pinia 实例
const pinia = createPinia()
// 使用 Pinia
app.use(pinia)
// 挂载应用
app.mount('#app')
使用 Pinia 在组件之间发送事件
发送事件的组件 (SenderComponent.vue)
<template>
<button @click="sendMessage">Send Message</button>
</template>
<script setup>
import { useMainStore } from '@/stores/index'
const mainStore = useMainStore()
function sendMessage() {
mainStore.updateMessage('Hello from Sender')
}
</script>
监听事件的组件 (ReceiverComponent.vue)
<template>
<div>{{ message }}</div>
</template>
<script setup>
import { useMainStore } from '@/stores/index'
const mainStore = useMainStore()
const message = computed(() => mainStore.message)
</script>
10. 使用自定义 Hook
Vue 3 的 Composition API 支持自定义 Hook,可以通过封装一些通用逻辑来简化组件间的通信。
示例:
// src/hooks/useCounter.js
import { ref, onMounted } from 'vue';
export function useCounter(initialValue) {
const count = ref(initialValue);
function increment() {
count.value++;
}
return { count, increment };
}
然后在组件中使用:
<template>
<button @click="increment">{{ count }}</button>
</template>
<script setup>
import { useCounter } from '@/hooks/useCounter';
const { count, increment } = useCounter(0);
</script>
以上的方法都可以在Vue3中得到良好体现,具体选择哪种看自己项目需求和个人爱好来,一般都是会按照pinia 或者 vuex之类的即可解决项目组件间的通讯问题了结合props、provide/inject以及自定义hooks等足够用了。
到此这篇关于一次搞清Vue3中组件通讯的全部方式的文章就介绍到这了,更多相关Vue3组件通讯方式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
