Vue3組件通信的方法大全
一、 父子通信:最親密、最常見的“家庭內(nèi)部對話”
這是最基礎(chǔ)也是最重要的通信方式,就像父母和孩子之間的日常交流。
1. Props (父 -> 子)
- 一句話解釋:父親(父組件)遞給兒子(子組件)一本《家規(guī)》(數(shù)據(jù)),兒子必須遵守。
- 幽默比喻:這就是“龍生龍,鳳生鳳,老鼠的兒子會打洞”。父親有什么“遺傳基因”(數(shù)據(jù)),就通過
props傳給兒子。兒子可以“看”和“用”這本家規(guī),但不能直接修改,否則就是“大逆不道”(單向數(shù)據(jù)流原則)。 - 使用方法:
- 父組件 (
Parent.vue):通過屬性綁定的方式傳值。
<template> <ChildComponent name="訾博" :age="18" /> </template> <script setup> import ChildComponent from './ChildComponent.vue'; </script>
- 子組件 (
ChildComponent.vue):使用defineProps接收。
<template>
<p>大家好,我叫{{ name }},今年{{ age }}歲。</p>
</template>
<script setup>
// 接收父組件傳來的props
const props = defineProps({
name: String,
age: {
type: Number,
required: true,
default: 10
}
});
</script>
2. Emits (子 -> 父)
- 一句話解釋:兒子(子組件)有事要向父親(父組件)匯報,就大喊一聲(觸發(fā)事件)。
- 幽默比喻:兒子在自己房間里考試得了100分,他不能直接沖到父親的賬本上把自己的零花錢改了。他得跑到客廳大喊:“爸!我考了100分!”(
$emit('got-full-marks', 100))。父親聽到了,自然會決定給他加多少零花錢(在父組件的事件監(jiān)聽函數(shù)里處理)。 - 使用方法:
子組件 (ChildComponent.vue):使用defineEmits聲明事件,然后通過emit函數(shù)觸發(fā)。
<template>
<button @click="tellDad">告訴爸爸我長大了</button>
</template>
<script setup>
// 聲明要觸發(fā)的事件
const emit = defineEmits(['grow-up']);
function tellDad() {
// 觸發(fā)事件,并可以傳遞參數(shù)
emit('grow-up', '我已經(jīng)會自己寫代碼了!');
}
</script>
父組件 (Parent.vue):在子組件標簽上使用@或v-on監(jiān)聽事件。
<template>
<ChildComponent @grow-up="handleChildGrowUp" />
<p>來自兒子的消息:{{ messageFromChild }}</p>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const messageFromChild = ref('');
function handleChildGrowUp(message) {
messageFromChild.value = message;
}
</script>
3. v-model (雙向綁定語法糖)
- 一句話解釋:
props和emits的組合套餐,專門用于父子組件間的數(shù)據(jù)同步。 - 幽默比喻:這就像一個對講機。父親可以通過對講機向兒子發(fā)號施令(
props),兒子也能通過同一個對講機回應(yīng)情況(emits),兩邊信息實時同步。 - 使用方法:Vue3的
v-model更靈活,可以有多個。
子組件 (CustomInput.vue):
<template>
<input :value="modelValue" @input="emit('update:modelValue', $event.target.value)" />
</template>
<script setup>
defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
</script>
父組件 (Parent.vue):
<template>
<CustomInput v-model="searchText" />
<p>你在搜索:{{ searchText }}</p>
</template>
<script setup>
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';
const searchText = ref('');
</script>
4. ref / $refs (父 -> 子)
- 一句話解釋:父親直接拿到兒子的“遙控器”,可以命令兒子做某些具體動作(調(diào)用方法、訪問屬性)。
- 幽默比喻:這有點“霸道總裁”,不通過商量(事件),直接命令。比如父親想讓兒子現(xiàn)在立刻馬上去做個俯臥撐。這種方式不常用,因為它破壞了組件的封裝性,屬于“最后的手段”。
- 使用方法:
子組件 (ChildComponent.vue):使用defineExpose暴露方法或?qū)傩浴?/p>
<template>
<p>我是一個深藏不露的組件</p>
</template>
<script setup>
import { ref } from 'vue';
const doPushUp = () => {
console.log('正在做俯臥撐...');
};
// 把doPushUp方法暴露給父組件
defineExpose({
doPushUp
});
</script>
父組件 (Parent.vue):
<template>
<ChildComponent ref="childRef" />
<button @click="commandChild">命令兒子</button>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const childRef = ref(null);
function commandChild() {
// 通過.value訪問到子組件實例,并調(diào)用其暴露的方法
childRef.value.doPushUp();
}
</script>
二、 跨代通信:當(dāng)“爺爺”想和“孫子”說話
如果組件嵌套很深,一層一層地props下去,會累死人,這叫“Props Drilling”(屬性鉆探地獄)。為了避免這種情況,我們有更優(yōu)雅的方案。
5. Provide / Inject
- 一句話解釋:祖先組件提供一個“共享寶藏”,任何后代組件都可以按“暗號”注入并使用它。
- 幽默比喻:這就像你們訾家的祖?zhèn)髅胤健@献孀冢ㄗ嫦冉M件)通過
provide把秘方藏在一個地方,并告訴后代“暗號”是什么。任何一個姓訾的子孫(后代組件),無論隔了多少代,只要報出暗號(inject),就能拿到這個秘方。外人(非后代組件)是拿不到的。 - 使用方法:
祖先組件 (GrandParent.vue):
<template>
<ParentComponent />
</template>
<script setup>
import { provide, ref } from 'vue';
const themeColor = ref('dark');
// 提供數(shù)據(jù),'theme'是暗號
provide('theme', themeColor);
</script>
后代組件 (GrandChild.vue):
<template>
<div :style="{ color: theme }">我是孫子組件,我用的是祖?zhèn)髦黝}色。</div>
</template>
<script setup>
import { inject } from 'vue';
// 注入數(shù)據(jù),'theme'是暗號
const theme = inject('theme');
</script>
三、 任意組件通信:當(dāng)“隔壁老王”想找你聊天
對于兩個沒有任何親緣關(guān)系的組件,如何進行交流?
6. Pinia (官方推薦的狀態(tài)管理庫)
- 一句話解釋:建立一個“全局中央銀行”(Store),所有組件都可以來這里存錢(修改state)、取錢(讀取state)或辦理業(yè)務(wù)(調(diào)用actions)。
- 幽默比喻:想象一下,整個應(yīng)用是一個城市,Pinia就是這個城市的中央銀行。無論你是住在城東的A組件,還是城西的B組件,大家共用一個銀行賬戶。A組件往里存了100塊,B組件馬上就能查到余額變化。它規(guī)范、安全、可追溯(有DevTools),是管理復(fù)雜應(yīng)用狀態(tài)的“金標準”。
- 使用方法:
定義Store (/stores/user.js):
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
name: '訾博',
isLoggedIn: false,
}),
actions: {
login() {
this.isLoggedIn = true;
},
},
});
在任意組件中使用:
<template>
<p v-if="userStore.isLoggedIn">歡迎回來, {{ userStore.name }}!</p>
<button @click="userStore.login()">登錄</button>
</template>
<script setup>
import { useUserStore } from '@/stores/user';
const userStore = useUserStore();
</script>
7. Mitt / Tiny-emitter (全局事件總線)
- 一句話解釋:創(chuàng)建一個全局的“廣播站”,一個組件可以向某個頻道廣播,另一個組件可以收聽這個頻道。
- 幽默比喻:Vue2時代的EventBus就像一個公共的對講機頻道。任何人都可以拿起來喊話,也任何人都可以收聽。這在小型應(yīng)用里很方便,但在大型應(yīng)用里,你不知道是誰在喊話,也不知道誰在聽,容易造成混亂。Vue3官方移除了這個功能,但我們可以用
mitt這樣的小庫來自己實現(xiàn)。 - 使用方法:
創(chuàng)建廣播站 (/utils/emitter.js):
import mitt from 'mitt'; const emitter = mitt(); export default emitter;
組件A (發(fā)送方):
<script setup>
import emitter from '@/utils/emitter';
function sendMessage() {
emitter.emit('some-event', '來自A組件的問候');
}
</script>
組件B (接收方):
<script setup>
import emitter from '@/utils/emitter';
import { onMounted, onUnmounted } from 'vue';
onMounted(() => {
emitter.on('some-event', (message) => {
console.log(message); // "來自A組件的問候"
});
});
// 記住,一定要在組件卸載時取消監(jiān)聽,否則會內(nèi)存泄漏!
onUnmounted(() => {
emitter.off('some-event');
});
</script>
總結(jié)與老師的忠告
訾博同學(xué),我們來畫個重點,做個總結(jié):
| 場景 | 推薦方法 | 核心思想 | 推薦指數(shù) |
|---|---|---|---|
| 父 -> 子 | Props | 單向數(shù)據(jù)流,清晰明了 | ★★★★★ |
| 子 -> 父 | Emits | 事件觸發(fā),解耦 | ★★★★★ |
| 父子雙向綁定 | v-model | props和emits的語法糖 | ★★★★★ |
| 跨代通信 | Provide / Inject | 依賴注入,避免屬性鉆探 | ★★★★☆ |
| 復(fù)雜應(yīng)用/任意組件 | Pinia | 集中式狀態(tài)管理,可預(yù)測 | ★★★★★ |
| 簡單應(yīng)用/任意組件 | Mitt (事件總線) | 發(fā)布訂閱,簡單靈活 | ★★★☆☆ |
| 父組件調(diào)用子組件方法 | ref / defineExpose | 直接引用,應(yīng)急手段 | ★★☆☆☆ |
為師的忠告:
- 首選“家庭內(nèi)部”方案:優(yōu)先使用
Props和Emits。這是Vue設(shè)計的核心,能讓你的數(shù)據(jù)流向最清晰、最容易維護。 - 避免“屬性鉆探”:當(dāng)
Props需要傳遞超過兩層時,就應(yīng)該立刻考慮使用Provide / Inject。 - 擁抱“中央銀行”:當(dāng)多個組件共享同一份狀態(tài)(比如用戶信息、主題設(shè)置),并且這個狀態(tài)會被多個組件修改時,不要猶豫,直接上
Pinia。它能讓你的應(yīng)用狀態(tài)變得井井有條,而不是一團亂麻。 - 慎用“大喇叭”和“遙控器”:
Mitt和ref都有其用武之地,但它們也更容易導(dǎo)致代碼難以追蹤和維護。把它們當(dāng)作你的“秘密武器”,非必要不使用。
專用于背誦的內(nèi)容
訾博,把下面這段口訣背下來,面試和實戰(zhàn)中定能助你一臂之力!
Vue3通信口訣
父傳子,用 Props,兒子不能隨便改。
子傳父,靠 Emits,爹聽事件樂開懷。
雙向綁,v-model,省事方便真不賴。
爺孫傳,Provide,Inject 注入接過來。
兄弟情,狀態(tài)亂,Pinia 銀行管起來。
事件總線 Mitt 在,偶爾用用別依賴。
父控子,用 ref,expose 暴露才存在。
牢記最佳實踐,代碼整潔人人愛!
以上就是Vue3組件通信的方法大全的詳細內(nèi)容,更多關(guān)于Vue3組件通信的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決VUE項目IIS部署后接口請求405錯誤問題(Method Not Allowed)
通過排查和修改IIS處理程序映射,添加ServerSideIncludeModule模塊,解決了StaticFileModule模塊報錯的問題,最終使得POST請求可以正常訪問2025-12-12
vue+iview框架實現(xiàn)左側(cè)動態(tài)菜單功能的示例代碼
這篇文章主要介紹了vue+iview框架實現(xiàn)左側(cè)動態(tài)菜單功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07
vue如何通過props方式在子組件中獲取相應(yīng)的對象
這篇文章主要介紹了vue如何通過props方式在子組件中獲取相應(yīng)的對象,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04
Vue+Element實現(xiàn)動態(tài)生成新表單并添加驗證功能
這篇文章主要介紹了Vue+Element實現(xiàn)動態(tài)生成新表單并添加驗證功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-05-05
如何使用fetchEventSource實現(xiàn)sse流式請求
這篇文章主要介紹了如何使用fetchEventSource實現(xiàn)sse流式請求問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
微信內(nèi)置開發(fā) iOS修改鍵盤換行為搜索的解決方案
今天小編就為大家分享一篇微信內(nèi)置開發(fā) iOS修改鍵盤換行為搜索的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11

