Vue3組件間通信機制方法深入理解
什么是組件?
在 Vue3 中,組件是構(gòu)建應(yīng)用界面的核心概念之一。組件可以看作是可復(fù)用、自包含和可組合的代碼塊,用于封裝 UI 元素和相應(yīng)的行為邏輯。
通俗來說就是,組件(Component)是一種對數(shù)據(jù)和方法的簡單封裝,每一個組件有自己單獨的邏輯,并且可以分別管理。不同的組件組合在一起,就形成了頁面。所以,每一個Web頁面可以抽象成是不同組件組合而成的,頁面只是這些組件的一個容器。并且這些組件可以在不影響程序運行的情況下,隨時被替換,利用這種組件化的思想可以將一個巨大的東西拆分成很多小模塊,也是現(xiàn)代前端框架的核心思想之一。
在 Vue 中,通常一個應(yīng)用會以一顆嵌套的組件樹的形式來組織,如圖所示:

上圖中將整體頁面為一個根組件,然后根組件下有三個子組件,分別是頁頭組件、內(nèi)容區(qū)組件和側(cè)邊欄組件。在內(nèi)容區(qū)組件下,又細分出兩個內(nèi)容組件,而側(cè)邊欄組件則有三個側(cè)邊欄內(nèi)容組件。所有組件整齊排列,按照樹形結(jié)構(gòu)組合,這就是 Vue 內(nèi)組件的組織結(jié)構(gòu)。
另外 Vue 3 的組件還具有以下特點:
模塊化:組件以模塊化的方式進行定義和使用,每個組件都有獨立的作用域,使得代碼更加結(jié)構(gòu)化和可維護。組件可根據(jù)需要進行拆分,形成層次化的組件樹結(jié)構(gòu)。
復(fù)用性:組件是可復(fù)用的,可以在應(yīng)用中多次使用。通過將 UI 元素和相關(guān)的邏輯封裝為組件,可以避免代碼重復(fù),并且可以輕松地在不同的上下文中重用組件。
可組合性:組件可以通過父子組件之間的嵌套與組合,形成更大規(guī)模的應(yīng)用界面。通過傳遞屬性 prop 和監(jiān)聽事件 emit,組件之間可以進行數(shù)據(jù)和通信的交互。
響應(yīng)式:組件內(nèi)部的數(shù)據(jù)可以使用 Vue 3 的響應(yīng)式系統(tǒng)進行管理,當數(shù)據(jù)發(fā)生變化時,組件會自動更新視圖。通過響應(yīng)式系統(tǒng),可以實現(xiàn)數(shù)據(jù)的雙向綁定和自動渲染。
生命周期鉤子函數(shù):Vue 3 的組件具有一系列的生命周期鉤子函數(shù),用于在組件不同的生命周期階段執(zhí)行特定的代碼邏輯。生命周期鉤子函數(shù)可以幫助開發(fā)者控制組件的行為和實現(xiàn)特定的功能。
單文件組件:Vue 3 支持使用單文件組件(.vue 文件)的方式來定義和編寫組件。單文件組件將組件的模板、樣式和邏輯都封裝在一個文件中,提高了代碼的可讀性和維護性。
組件定義
一個 Vue 組件的結(jié)構(gòu)通常包括三個部分:模板(Template)、腳本(Script)和樣式(Style)。這些部分一般會放在一個單文件組件(.vue 文件)中,也可以分離成三個獨立的文件。
下面是一個典型的 Vue 組件的結(jié)構(gòu)示例:
<template> <!-- 模板部分 --> </template> <script setup> // 腳本部分 </script> <style> /* 樣式部分 */ /* CSS 樣式規(guī)則 */ </style>
其中:
模板(Template):模板部分定義了組件的結(jié)構(gòu)和布局,使用 HTML 和 Vue 的模板語法編寫。在模板中可以插入動態(tài)數(shù)據(jù)和表達式,并通過指令(如
v-bind、v-if)和事件綁定等方式與組件的數(shù)據(jù)和行為進行交互。腳本(Script):腳本部分是組件的邏輯核心,使用 JavaScript 或 TypeScript 編寫。在腳本中,可以定義組件的屬性、計算屬性、方法、生命周期鉤子函數(shù)等。通過腳本,可以處理組件的數(shù)據(jù)邏輯、事件響應(yīng)等功能。
樣式(Style):樣式部分定義了組件的樣式規(guī)則,使用 CSS 或預(yù)處理器(如 Sass、Less)編寫。可以為組件元素添加類名、樣式選擇器等,來對組件進行樣式修飾和美化。
這種將模板、腳本和樣式封裝在一個單文件組件中的方式,可以提高代碼的可讀性和維護性,并且使得組件的結(jié)構(gòu)更加清晰和獨立。通過單文件組件,我們可以更好地組織和管理組件的相關(guān)資源,并方便地重用和維護組件。
組件注冊
在 Vue 中,如果要使用自定義組件,第一步需要做的就是將其注冊到應(yīng)用中。Vue 組件的注冊可以有兩種方式:全局注冊和局部注冊。
全局注冊:全局注冊的組件可以在整個應(yīng)用的任何地方使用,無需額外的導入或注冊操作。
全局注冊組件的方法是在 main.ts 文件中使用
app.component方法。例如,將自定義組件my-component進行全局注冊:import { createApp } from 'vue'; import App from './App.vue'; import MyComponent from './components/MyComponent.vue'; const app = createApp(App); app.component('my-component', MyComponent); app.mount('#app');在上述示例中,我們首先使用
createApp創(chuàng)建應(yīng)用實例,并將根組件App作為參數(shù)傳入。然后,使用app.component方法全局注冊名為my-component的組件,并將其與MyComponent組件關(guān)聯(lián)。最后,通過app.mount將應(yīng)用掛載到頁面中的 DOM 元素上。在全局注冊后,我們可以在任何組件的模板中使用
<my-component></my-component>標簽來引入和使用該組件,無需在局部組件中重新注冊。局部注冊:局部注冊的組件只能在其所屬的組件內(nèi)部使用,無法在其他組件(包括子組件)中直接使用。
在組合式 API 中組件局部注冊時直接引入,然后直接調(diào)用即可。例如:
<script setup> import MyComponent from './MyComponent.vue'; javascript:void(0)</script> <template> <!-- 使用局部注冊的子組件 --> <my-component></my-component> </template>在上述代碼中,
<script setup>部分引入了MyComponent組件,并且不需要使用app.component進行額外的局部注冊。直接在模板中使用<my-component></my-component>即可使用這個局部注冊的組件。
通過全局或局部注冊組件,我們可以在應(yīng)用中靈活地使用和組織組件,實現(xiàn)不同層次的封裝和復(fù)用。
組件通信
在 Vue 中,組件之間的通信,大致可以分為以下四種情況:父組件向子組件通信、子組件向父組件通信、父組件向隔代子組件通信和非父子組件之間的通信。如圖:

四種通信模式涵蓋了 Vue 中組件和組件通信的所有情況,解決方法如下:
- 父組件向子組件傳遞數(shù)據(jù):使用組件的 props 實現(xiàn)。
- 子組件向父組件傳遞數(shù)據(jù):通過自定義事件實現(xiàn)。
- 父組件向隔代子組件傳遞數(shù)據(jù):使用訂閱發(fā)布實現(xiàn),使用 provide/inject 在父組件提供數(shù)據(jù),在后代組件中注入數(shù)據(jù)。
- 非父子組件之間傳遞數(shù)據(jù):使用第三方狀態(tài)管理實現(xiàn),如 Pinia。
根據(jù)不同的場景和需求,選擇適合的通信方式來進行組件之間的通信。
使用 Props 通信
Props 關(guān)鍵字代表開發(fā)者在組件上注冊的一些自定義屬性,然后父組件通過子組件的 Props 屬性將數(shù)據(jù)直接傳遞到子組件內(nèi)部,供子組件調(diào)用處理。
需要注意的是,Props 傳遞的數(shù)據(jù)全部為單向流數(shù)據(jù),即只能從父組件向子組件傳遞,不能子組件向父組件傳遞。所以,在使用 Props 進行組件之間通信時,需要首先在子組件內(nèi)定義 Props,然后在父組件內(nèi)調(diào)用,代碼如下:
//子組件 ChildComponent.vue
<template>
<p>{{ message }}</p>
</template>
<script setup lang="ts">
defineProps<{
message?:string
}>()
</script>
在子組件中,使用 defineProps() 方法定義了一個名為 message 的 prop,類型為字符串。通過在模板中使用雙花括號語法 {{ message }},可以顯示接收到的來自父組件的數(shù)據(jù)。
//父組件 Parent.vue
<script setup lang="ts">
import ChildComponent from './ChildComponent.vue'
const parentMessage=ref<string>("Hello from parent component!")
</script>
<template>
<child-component :message="parentMessage"></child-component>
</template>
在父組件中,定義了一個名為 parentMessage 的數(shù)據(jù)屬性,并將其綁定到子組件的 prop 上。通過在子組件標簽上使用冒號語法 :message="parentMessage",將父組件的 parentMessage 數(shù)據(jù)傳遞給子組件的 message prop。
使用以上代碼,父組件就能夠通過 props 向子組件傳遞數(shù)據(jù)了。在子組件中,可以直接使用該數(shù)據(jù)進行展示或進一步處理。這種父組件向子組件傳遞數(shù)據(jù)的方式非常常見,并且在 Vue 組件開發(fā)中被廣泛使用。
另外,如果想給 Props 定義的屬性一個初始值,可以使用 withDefaults() 方法,代碼如下:
<script setup lang="ts">
withDefaults(defineProps<{message?:string}>(),{
message:'這是默認值'
})
</script>
withDefaults() 方法接收的第一個參數(shù)是 Props 定義,第二個參數(shù)則是這些 Props 定義的屬性的默認值。并且這里在定義 Props 的時候,采用 TypeScript 的可選屬性定義組件屬性,即再屬性名稱后面添加問號,代表當前 Props 屬性為非必傳屬性,子組件使用默認值來進行渲染。
使用自定義事件通信
在 Vue 3 的組合式 API 中,組件的自定義事件是通過 defineEmits() 方法定義。然后在需要被調(diào)用的地方發(fā)射自定義事件給父組件,同時,父組件通過 v-on 指令將本身的處理函數(shù)與子組件發(fā)射的自定義事件相綁定,從而實現(xiàn)子組件向父組件通信的過程。
下面是一個示例代碼:
//子組件 ChildComponent.vue
<template>
<button @click="emit('btnClick', message)">傳遞</button>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const message = ref<string>("子組件消息")
const emit = defineEmits<{
(eventName: 'btnClick', message: string): void
}>()
</script>
上述代碼中,我們在 <script setup> 中,使用 defineEmits 來定義了一個 btnClick 的自定義事件。然后,我們將 sendMessage 方法進行了修改,使其調(diào)用 emit 方法并傳遞了 btnClick 事件名稱和 message 變量的值。
這樣,當子組件的按鈕被點擊時,就會觸發(fā) btnClick 事件,并將 message 的值傳遞給父組件。父組件可以監(jiān)聽該事件并進行相應(yīng)的處理。
//父組件 Parent.vue
<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const message = ref<string>("父組件消息")
const handle = (msg:string):void=>{
message.value=msg
}
</script>
<template>
<p>消息: {{ message }}</p>
<child-component @btn-click="handle"></child-component>
</template>
在父組件中,我們使用 @btn-click 監(jiān)聽子組件觸發(fā)的 btn-click 自定義事件,并將 handle 方法指定為事件處理函數(shù)。
當子組件中的按鈕被點擊時,會觸發(fā) btn-click 事件并將消息作為參數(shù)傳遞給父組件的 handle 方法。在 handle 方法中,我們將接收到的消息更新到 message 變量上,從而實現(xiàn)父組件接收子組件發(fā)送的消息并進行處理的效果。
使用訂閱發(fā)布通信
Props 屬性負責父組件向子組件傳遞數(shù)據(jù),子組件可以通過自定義事件向父組件傳遞數(shù)據(jù)。但是如果兩個組件不是父子組件關(guān)系,而是深度嵌套的組件,并且深層子組件只需要父組件的部分內(nèi)容,這個時侯如果使用 Props 屬性逐級傳下去,將會顯得非常麻煩而且容易出錯。針對這種情況,Vue 推出了發(fā)布訂閱進行通信,即 Provider/Inject 通信。
Provider/Inject 通信,需要有一個 Provider 和一個或者多個 Inject。在父組件中,Provider 負責提供數(shù)據(jù),深層子組件里的 Inject 負責讀取數(shù)據(jù)。這種通信方式,不管父子組件中間相隔多久,都是可以實現(xiàn)的。
例如這里的組件層級關(guān)系如下:
ProjectInjectComponent ﹂ProjectInjectChild ﹂ProjectInjectGrandson
在 ProjectlnjectComponent 中使用 Provide 先發(fā)布一條數(shù)據(jù), 然后在孫組件 ProjectInjectGrandson 中通過 Inject 訂閱這條數(shù)據(jù)并顯示。代碼如下:
//ProjectInjectComponent.vue(父組件)
<script lang="ts" setup>
import { provide, ref } from 'vue';
import ProjectInjectChild from './ProjectInjectChild.vue';
const message = ref<string>("ProjectInjectComponent 組件消息")
//發(fā)布數(shù)據(jù),key:message
provide('message',message);
</script>
<template>
<ProjectInjectChild></ProjectInjectChild>
</template>
//ProjectInjectChild.vue(子組件)
<script lang="ts" setup>
import ProjectInjectGrandson from './ProjectInjectGrandson.vue';
</script>
<template>
<ProjectInjectGrandson></ProjectInjectGrandson>
</template>
//ProjectInjectGrandson.vue(孫組件)
<script lang="ts" setup>
import { inject, ref } from 'vue';
//訂閱數(shù)據(jù) key:message,defaultValue:"消息"
const message = inject<string>('message',"消息")
</script>
<template>
<h2>{{ message }}</h2>
</template>
在 ProjectInjectComponent 組件中通過 Provide 發(fā)布了一個名為 message 數(shù)據(jù);在嵌套最底層的 ProvideInjectGrandson 組件中通過 Inject 讀取父組件發(fā)布的 message 數(shù)據(jù),并渲染在頁面上。因為父組件中的 message 是響應(yīng)式數(shù)據(jù),所以父組件中的數(shù)據(jù)會同步更新到嵌套的子組件中,最終將更新后的數(shù)據(jù)重新渲染到頁面。
總結(jié)
到此這篇關(guān)于Vue3組件間通信機制方法的文章就介紹到這了,更多相關(guān)Vue3組件間通信機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vuex中如何getters動態(tài)獲取state的值
這篇文章主要介紹了Vuex中如何getters動態(tài)獲取state的值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
前端在el-dialog中嵌套多個el-dialog代碼實現(xiàn)
最近使用vue+elementUI做項目,使用過程中很多地方會用到dialog這個組件,有好幾個地方用到了dialog的嵌套,下面這篇文章主要給大家介紹了關(guān)于前端在el-dialog中嵌套多個el-dialog代碼實現(xiàn)的相關(guān)資料,需要的朋友可以參考下2024-01-01
Vue2+Echarts封裝組件之專注邏輯,圖表生成自動化方式
文章介紹了使用Vue2封裝的Echarts圖表組件,簡化了圖表的生成和渲染過程,提供了多種圖表類型和交互功能,提高了開發(fā)效率,幫助開發(fā)者專注于業(yè)務(wù)邏輯的開發(fā)2025-02-02

