Vue3優(yōu)雅的實(shí)現(xiàn)跨組件通信的常用方法總結(jié)
前言
開(kāi)發(fā)中經(jīng)常會(huì)遇到跨組件通信的場(chǎng)景。props 逐層傳遞的方法實(shí)在是太不優(yōu)雅了,所以今天總結(jié)下可以更加簡(jiǎn)單的跨組件通信的一些方法。

依賴注入

<!-- App.vue -->
<script setup lang="ts">
import { ref, provide } from "vue";
import Child from "./components/Child.vue";
const count = ref(0)
const updateCount = () => count.value ++
provide("count", {count, updateCount})
</script>
<template>
<h4>公眾號(hào):萌萌噠草頭將軍</h4>
<div>{{ count }}</div>
<button @click="updateCount">change</button>
<Child />
</template>
<!-- Child.vue --> <template> <Other /> </template> <script setup lang='ts'> import Other from "./other.vue" </script>

在 setup 組件中,使用 inject 跨組件通信是最佳的方案。所以該模式下,是沒(méi)有提供event bus 事件總線。
但是在 option api 模式下,還需要額外的注冊(cè),顯的有點(diǎn)麻煩。
<script lang='ts'>
export default {
emits: ["some-name"]
}
</script>
屬性透?jìng)?/h2>
<!-- App.vue -->
<script setup lang="ts">
import { ref, provide } from "vue";
import Attr from "./components/Attr.vue";
const count = ref(0)
const updateCount = () => count.value ++
provide("count", {count, updateCount})
</script>
<template>
<h4>公眾號(hào):萌萌噠草頭將軍</h4>
<div>{{ count }}</div>
<button @click="updateCount">change</button>
<Attr :count="count" :updateCount="updateCount" />
</template>
<!-- Attr.vue -->
<template>
<div>attr component</div>
<Child v-bind="$attrs" />
</template>
<script setup lang='ts'>
import Child from './Child.vue';
</script>
<!-- App.vue -->
<script setup lang="ts">
import { ref, provide } from "vue";
import Attr from "./components/Attr.vue";
const count = ref(0)
const updateCount = () => count.value ++
provide("count", {count, updateCount})
</script>
<template>
<h4>公眾號(hào):萌萌噠草頭將軍</h4>
<div>{{ count }}</div>
<button @click="updateCount">change</button>
<Attr :count="count" :updateCount="updateCount" />
</template>
<!-- Attr.vue --> <template> <div>attr component</div> <Child v-bind="$attrs" /> </template> <script setup lang='ts'> import Child from './Child.vue'; </script>

屬性透?jìng)鬟@種方式類(lèi)似于react中手動(dòng)透?jìng)鲗傩?。感覺(jué)有點(diǎn)暴力,但是又特別方便快捷。
function App (props) {
return <Other {...props} />
}
Vue中默認(rèn)透?jìng)鞯膶傩杂?style、class、key。如果子組件也存在class、style,則會(huì)自動(dòng)合并class、style。
如果你的子組件是根組件時(shí),可以省略 v-bind="$attrs"。
<template> <Child /> </template>
狀態(tài)庫(kù)
狀態(tài)管理庫(kù)我們以Pinia為例。
<!-- App.vue -->
<script setup lang="ts">
import Other from "./components/Other.vue";
import { useCounterStore } from "./store/index"
const state = useCounterStore()
</script>
<template>
<h4>公眾號(hào):萌萌噠草頭將軍</h4>
<div>{{ count }}</div>
<button @click="updateCount">change</button>
<Other />
</template>
import { defineStore } from "pinia"
import { ref } from "vue"
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function updateCount() {
count.value++
}
return { count, updateCount }
})
<!-- Other.vue -->
<template>
<div>pinia store</div>
<div>{{ state.count }}</div>
<button @click="state.updateCount">other change</button>
</template>
<script setup lang='ts'>
import { useCounterStore } from '../store';
const state = useCounterStore()
</script>

狀態(tài)管理庫(kù)最大的缺點(diǎn)是,沒(méi)法使用解構(gòu)語(yǔ)法。因?yàn)檫@會(huì)導(dǎo)致失去響應(yīng)式的能力。
事件總線
事件總線(event bus)比較特殊,因?yàn)樵诮M合式API里不支持該方式,所以下面的例子適合 Option API 組件。
<!-- App.vue -->
<script setup lang="ts">
import { ref } from "vue";
import Other from "./components/Other.vue";
const count = ref(0)
const updateCount = () => count.value ++
</script>
<template>
<h4>公眾號(hào):萌萌噠草頭將軍</h4>
<div>{{ count }}</div>
<button @click="updateCount">change</button>
<Other @updateCount="updateCount()" />
</template>
<!-- Other.vue -->
<template>
<div>eventBus store</div>
<button @click="$emit('updateCount')">other change</button>
</template>
<script lang='ts'>
export default {
emits: ["updateCount"]
}
</script>
事件總線更適合傳遞事件。
自定義事件
但是有時(shí)候,你可能非常想使用事件總線的方式在 setup 組件中傳遞事件,這時(shí)候我們可以使用自定義的事件的方式實(shí)現(xiàn)這種功能。
下面是實(shí)現(xiàn)。
class EventBus {
constructor() {
this.events = {};
}
// 訂閱事件
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
// 發(fā)布事件
emit(eventName, eventData) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
eventCallbacks.forEach(callback => {
callback(eventData);
});
}
}
// 取消訂閱事件
off(eventName, callback) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
this.events[eventName] = eventCallbacks.filter(cb => cb !== callback);
}
}
}
export const eventBus = new EventBus()
<!-- App.vue -->
<script setup lang="ts">
import { ref } from "vue";
import Other from "./components/Other.vue";
import { eventBus } from "./store/eventBus";
const count = ref(0)
const updateCount = () => count.value ++
eventBus.on("updateCount", updateCount)
</script>
<template>
<h4>公眾號(hào):萌萌噠草頭將軍</h4>
<div>{{ count }}</div>
<button @click="updateCount">change</button>
<Other @updateCount="updateCount()" />
</template>
<!-- Other.vue -->
<template>
<div>eventBus</div>
<button @click="eventBus.emit('updateCount', null)">other change</button>
</template>
<script setup lang='ts'>
import { eventBus } from "../store/eventBus";
</script>

當(dāng)然,我們這里不止可以使用 event bus,發(fā)布訂閱模式也很適合??梢詤⒖嘉乙郧暗脑O(shè)計(jì)模式的文章實(shí)現(xiàn)這個(gè)功能。
總結(jié)
每種方式都有自己的優(yōu)點(diǎn)和缺點(diǎn),根據(jù)使用場(chǎng)景選擇最合適的才能算是最優(yōu)的方案。
以上就是Vue3優(yōu)雅的跨組件通信的常用方法總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Vue3跨組件通信的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決vue單頁(yè)面修改樣式無(wú)法覆蓋問(wèn)題
這篇文章主要介紹了vue單頁(yè)面修改樣式無(wú)法覆蓋問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
Vue組件實(shí)現(xiàn)旋轉(zhuǎn)木馬動(dòng)畫(huà)
這篇文章主要為大家詳細(xì)介紹了Vue組件實(shí)現(xiàn)旋轉(zhuǎn)木馬動(dòng)畫(huà)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
vue導(dǎo)出excel多層表頭的實(shí)現(xiàn)方案詳解
這篇文章主要為大家詳細(xì)介紹了vue導(dǎo)出excel多層表頭的實(shí)現(xiàn)方案,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04
vue導(dǎo)出excel無(wú)法打開(kāi)問(wèn)題及解決
在Vue項(xiàng)目中導(dǎo)出Excel文件時(shí),需在請(qǐng)求中設(shè)置responseType為'blob'或'arraybuffer',否則文件可能損壞無(wú)法打開(kāi),正確配置確保瀏覽器正確解析二進(jìn)制數(shù)據(jù)流,生成有效Excel文件2025-08-08
vue 組件中使用 transition 和 transition-group實(shí)現(xiàn)過(guò)渡動(dòng)畫(huà)
本文給大家分享一下vue 組件中使用 transition 和 transition-group 設(shè)置過(guò)渡動(dòng)畫(huà),總結(jié)來(lái)說(shuō)可分為分為 name 版, js 鉤子操作類(lèi)名版, js 鉤子操作行內(nèi)樣式版,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2019-07-07

