Vue3優(yōu)雅的實(shí)現(xiàn)跨組件通信的常用方法總結(jié)
前言
開發(fā)中經(jīng)常會(huì)遇到跨組件通信的場景。props 逐層傳遞的方法實(shí)在是太不優(yōu)雅了,所以今天總結(jié)下可以更加簡單的跨組件通信的一些方法。
依賴注入
<!-- 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>公眾號:萌萌噠草頭將軍</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 跨組件通信是最佳的方案。所以該模式下,是沒有提供event bus 事件總線。
但是在 option api 模式下,還需要額外的注冊,顯的有點(diǎn)麻煩。
<script lang='ts'> export default { emits: ["some-name"] } </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>公眾號:萌萌噠草頭將軍</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>
屬性透傳這種方式類似于react中手動(dòng)透傳屬性。感覺有點(diǎn)暴力,但是又特別方便快捷。
function App (props) { return <Other {...props} /> }
Vue中默認(rèn)透傳的屬性有 style、class、key。如果子組件也存在class、style,則會(huì)自動(dòng)合并class、style。
如果你的子組件是根組件時(shí),可以省略 v-bind="$attrs"。
<template> <Child /> </template>
狀態(tài)庫
狀態(tài)管理庫我們以Pinia為例。
<!-- App.vue --> <script setup lang="ts"> import Other from "./components/Other.vue"; import { useCounterStore } from "./store/index" const state = useCounterStore() </script> <template> <h4>公眾號:萌萌噠草頭將軍</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)管理庫最大的缺點(diǎn)是,沒法使用解構(gòu)語法。因?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>公眾號:萌萌噠草頭將軍</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>公眾號:萌萌噠草頭將軍</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ù)使用場景選擇最合適的才能算是最優(yōu)的方案。
以上就是Vue3優(yōu)雅的跨組件通信的常用方法總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Vue3跨組件通信的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決Vue axios post請求,后臺獲取不到數(shù)據(jù)的問題方法
今天小編就為大家分享一篇解決Vue axios post請求,后臺獲取不到數(shù)據(jù)的問題方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08如何利用vscode-icons-js在Vue3項(xiàng)目中實(shí)現(xiàn)文件圖標(biāo)展示
在開發(fā)文件管理系統(tǒng)或類似的項(xiàng)目時(shí),我們常常需要根據(jù)文件類型展示對應(yīng)的文件圖標(biāo),這樣可以提高用戶體驗(yàn),本文將介紹如何在Vue3項(xiàng)目中利用vscode-icons-js庫,實(shí)現(xiàn)類似VSCode的文件圖標(biāo)展示效果,感興趣的朋友一起看看吧2024-08-08vue?循環(huán)動(dòng)態(tài)設(shè)置ref并獲取$refs方式
這篇文章主要介紹了vue?循環(huán)動(dòng)態(tài)設(shè)置ref并獲取$refs方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01使用vue3-print-nb實(shí)現(xiàn)打印pdf分頁代碼示例
這篇文章主要介紹了使用vue3-print-nb實(shí)現(xiàn)打印pdf分頁的相關(guān)資料,這種方法不僅適用于Vue3項(xiàng)目,也可以在其他前端框架中實(shí)現(xiàn)類似的打印分頁功能,需要的朋友可以參考下2024-10-10