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

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

四種通信模式涵蓋了 Vue 中組件和組件通信的所有情況,解決方法如下:
- 父組件向子組件傳遞數(shù)據(jù):使用組件的 props 實(shí)現(xiàn)。
- 子組件向父組件傳遞數(shù)據(jù):通過(guò)自定義事件實(shí)現(xiàn)。
- 父組件向隔代子組件傳遞數(shù)據(jù):使用訂閱發(fā)布實(shí)現(xiàn),使用 provide/inject 在父組件提供數(shù)據(jù),在后代組件中注入數(shù)據(jù)。
- 非父子組件之間傳遞數(shù)據(jù):使用第三方狀態(tài)管理實(shí)現(xiàn),如 Pinia。
根據(jù)不同的場(chǎng)景和需求,選擇適合的通信方式來(lái)進(jìn)行組件之間的通信。
使用 Props 通信
Props 關(guān)鍵字代表開(kāi)發(fā)者在組件上注冊(cè)的一些自定義屬性,然后父組件通過(guò)子組件的 Props 屬性將數(shù)據(jù)直接傳遞到子組件內(nèi)部,供子組件調(diào)用處理。
需要注意的是,Props 傳遞的數(shù)據(jù)全部為單向流數(shù)據(jù),即只能從父組件向子組件傳遞,不能子組件向父組件傳遞。所以,在使用 Props 進(jìn)行組件之間通信時(shí),需要首先在子組件內(nèi)定義 Props,然后在父組件內(nèi)調(diào)用,代碼如下:
//子組件 ChildComponent.vue
<template>
<p>{{ message }}</p>
</template>
<script setup lang="ts">
defineProps<{
message?:string
}>()
</script>
在子組件中,使用 defineProps() 方法定義了一個(gè)名為 message 的 prop,類(lèi)型為字符串。通過(guò)在模板中使用雙花括號(hào)語(yǔ)法 {{ message }},可以顯示接收到的來(lái)自父組件的數(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>
在父組件中,定義了一個(gè)名為 parentMessage 的數(shù)據(jù)屬性,并將其綁定到子組件的 prop 上。通過(guò)在子組件標(biāo)簽上使用冒號(hào)語(yǔ)法 :message="parentMessage",將父組件的 parentMessage 數(shù)據(jù)傳遞給子組件的 message prop。
使用以上代碼,父組件就能夠通過(guò) props 向子組件傳遞數(shù)據(jù)了。在子組件中,可以直接使用該數(shù)據(jù)進(jìn)行展示或進(jìn)一步處理。這種父組件向子組件傳遞數(shù)據(jù)的方式非常常見(jiàn),并且在 Vue 組件開(kāi)發(fā)中被廣泛使用。
另外,如果想給 Props 定義的屬性一個(gè)初始值,可以使用 withDefaults() 方法,代碼如下:
<script setup lang="ts">
withDefaults(defineProps<{message?:string}>(),{
message:'這是默認(rèn)值'
})
</script>
withDefaults() 方法接收的第一個(gè)參數(shù)是 Props 定義,第二個(gè)參數(shù)則是這些 Props 定義的屬性的默認(rèn)值。并且這里在定義 Props 的時(shí)候,采用 TypeScript 的可選屬性定義組件屬性,即再屬性名稱(chēng)后面添加問(wèn)號(hào),代表當(dāng)前 Props 屬性為非必傳屬性,子組件使用默認(rèn)值來(lái)進(jìn)行渲染。
使用自定義事件通信
在 Vue 3 的組合式 API 中,組件的自定義事件是通過(guò) defineEmits() 方法定義。然后在需要被調(diào)用的地方發(fā)射自定義事件給父組件,同時(shí),父組件通過(guò) v-on 指令將本身的處理函數(shù)與子組件發(fā)射的自定義事件相綁定,從而實(shí)現(xiàn)子組件向父組件通信的過(guò)程。
下面是一個(gè)示例代碼:
//子組件 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>
上述代碼中,我們?cè)?<script setup> 中,使用 defineEmits 來(lái)定義了一個(gè) btnClick 的自定義事件。然后,我們將 sendMessage 方法進(jìn)行了修改,使其調(diào)用 emit 方法并傳遞了 btnClick 事件名稱(chēng)和 message 變量的值。
這樣,當(dāng)子組件的按鈕被點(diǎn)擊時(shí),就會(huì)觸發(fā) btnClick 事件,并將 message 的值傳遞給父組件。父組件可以監(jiān)聽(tīng)該事件并進(jì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)聽(tīng)子組件觸發(fā)的 btn-click 自定義事件,并將 handle 方法指定為事件處理函數(shù)。
當(dāng)子組件中的按鈕被點(diǎn)擊時(shí),會(huì)觸發(fā) btn-click 事件并將消息作為參數(shù)傳遞給父組件的 handle 方法。在 handle 方法中,我們將接收到的消息更新到 message 變量上,從而實(shí)現(xiàn)父組件接收子組件發(fā)送的消息并進(jìn)行處理的效果。
使用訂閱發(fā)布通信
Props 屬性負(fù)責(zé)父組件向子組件傳遞數(shù)據(jù),子組件可以通過(guò)自定義事件向父組件傳遞數(shù)據(jù)。但是如果兩個(gè)組件不是父子組件關(guān)系,而是深度嵌套的組件,并且深層子組件只需要父組件的部分內(nèi)容,這個(gè)時(shí)侯如果使用 Props 屬性逐級(jí)傳下去,將會(huì)顯得非常麻煩而且容易出錯(cuò)。針對(duì)這種情況,Vue 推出了發(fā)布訂閱進(jìn)行通信,即 Provider/Inject 通信。
Provider/Inject 通信,需要有一個(gè) Provider 和一個(gè)或者多個(gè) Inject。在父組件中,Provider 負(fù)責(zé)提供數(shù)據(jù),深層子組件里的 Inject 負(fù)責(zé)讀取數(shù)據(jù)。這種通信方式,不管父子組件中間相隔多久,都是可以實(shí)現(xiàn)的。
例如這里的組件層級(jí)關(guān)系如下:
ProjectInjectComponent ﹂ProjectInjectChild ﹂ProjectInjectGrandson
在 ProjectlnjectComponent 中使用 Provide 先發(fā)布一條數(shù)據(jù), 然后在孫組件 ProjectInjectGrandson 中通過(guò) 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 組件中通過(guò) Provide 發(fā)布了一個(gè)名為 message 數(shù)據(jù);在嵌套最底層的 ProvideInjectGrandson 組件中通過(guò) Inject 讀取父組件發(fā)布的 message 數(shù)據(jù),并渲染在頁(yè)面上。因?yàn)楦附M件中的 message 是響應(yīng)式數(shù)據(jù),所以父組件中的數(shù)據(jù)會(huì)同步更新到嵌套的子組件中,最終將更新后的數(shù)據(jù)重新渲染到頁(yè)面。
總結(jié)
到此這篇關(guān)于Vue3組件間通信機(jī)制方法的文章就介紹到這了,更多相關(guān)Vue3組件間通信機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue監(jiān)聽(tīng)input標(biāo)簽的value值方法
今天小編就為大家分享一篇vue監(jiān)聽(tīng)input標(biāo)簽的value值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
使用vue-router完成簡(jiǎn)單導(dǎo)航功能【推薦】
vue-router是Vue.js官方提供的一套專(zhuān)用的路由工具庫(kù)。這篇文章主要介紹了使用vue-router完成簡(jiǎn)單導(dǎo)航功能,需要的朋友可以參考下2018-06-06
vue+swiper實(shí)現(xiàn)左右滑動(dòng)的測(cè)試題功能
這篇文章主要介紹了vue+swiper實(shí)現(xiàn)左右滑動(dòng)的測(cè)試題功能,本文通過(guò)實(shí)例代碼給大介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
Vue彈窗Dialog最佳使用方案實(shí)戰(zhàn)
這篇文章主要為大家介紹了極度舒適的Vue彈窗Dialog最佳使用方案實(shí)戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
vue結(jié)合axios與后端進(jìn)行ajax交互的方法
本篇文章主要介紹了vue結(jié)合axios與后端進(jìn)行ajax交互的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
vue實(shí)現(xiàn)聯(lián)動(dòng)選擇
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)聯(lián)動(dòng)選擇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03

