Vue開發(fā)之組件通信的常用方案全攻略
前言
在 Vue 開發(fā)中,組件通信是構(gòu)建復(fù)雜應(yīng)用的基礎(chǔ)。隨著 Vue 3 的普及,通信方式發(fā)生了不少變化(如 defineProps 的引入、EventBus 的退場)。本文將對比 Vue 2 與 Vue 3,帶你梳理最常用的 5 種通信方案。
一、 父子組件通信:最基礎(chǔ)的單向數(shù)據(jù)流
這是最常用的通信方式,遵循“Props 向下傳遞,Emit 向上通知”的原則。
1. Vue 2 經(jīng)典寫法
- 接收:使用
props選項。 - 發(fā)送:使用
this.$emit。
2. Vue 3 + TS 標(biāo)準(zhǔn)寫法
在 Vue 3 <script setup> 中,我們使用 defineProps 和 defineEmits。
父組件:Parent.vue
<template>
<ChildComponent :id="currentId" @childEvent="handleChild" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './Child.vue';
const currentId = ref<string>('001');
const handleChild = (msg: string) => {
console.log('接收到子組件消息:', msg);
};
</script>
子組件:Child.vue
<script setup lang="ts">
// 使用 TS 類型定義 Props
const props = defineProps<{
id: string
}>();
// 使用 TS 定義 Emits,具備更好的類型檢查
const emit = defineEmits<{
(e: 'childEvent', args: string): void;
}>();
const sendMessage = () => {
emit('childEvent', '這是來自子組件的參數(shù)');
};
</script>
二、 跨級調(diào)用:通過 Ref 訪問實例
有時父組件需要直接調(diào)用子組件的內(nèi)部方法。
1. Vue 2 模式
直接通過 this.$refs.childRef.someMethod() 調(diào)用。
2. Vue 3 模式(顯式暴露)
Vue 3 的組件默認(rèn)是關(guān)閉的。如果父組件想訪問子組件的方法,子組件必須使用 defineExpose。
子組件:Child.vue
<script setup lang="ts">
const childFunc = () => {
console.log('子組件方法被調(diào)用');
};
// 必須手動暴露,父組件才能訪問
defineExpose({
childFunc
});
</script>
父組件:Parent.vue
<template>
<Child ref="childRef" />
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import Child from './Child.vue';
// 這里的類型定義有助于獲得代碼提示
const childRef = ref<InstanceType<typeof Child> | null>(null);
onMounted(() => {
childRef.value?.childFunc();
});
</script>
三、 非父子組件通信:事件總線 (EventBus)
1. Vue 2 做法
利用一個新的 Vue 實例作為中央調(diào)度器。
import Vue from 'vue';
export const EventBus = new Vue();
// 組件 A 發(fā)送
EventBus.$emit('event', data);
// 組件 B 接收
EventBus.$on('event', (data) => { ... });
2. Vue 3 重要變更
Vue 3 官方已移除了 $on、$off 和 $once 方法,因此不再支持直接通過 Vue 實例創(chuàng)建 EventBus。
- 官方推薦方案:使用第三方庫
mitt或tiny-emitter。 - 補充:如果邏輯簡單,可以使用 Vue 3 的
provide/inject實現(xiàn)跨級通信。
provide / inject 示例:
1.祖先組件:提供數(shù)據(jù) (App.vue)
<template>
<div class="ancestor">
<h1>祖先組件</h1>
<p>當(dāng)前主題:{{ theme }}</p>
<Middle />
</div>
</template>
<script setup lang="ts">
import { ref, provide } from 'vue';
import Middle from './Middle.vue';
// 1. 定義響應(yīng)式數(shù)據(jù)
const theme = ref<'light' | 'dark'>('light');
// 2. 定義修改數(shù)據(jù)的方法(推薦在提供者內(nèi)部定義,保證數(shù)據(jù)流向清晰)
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
};
// 3. 注入 key 和對應(yīng)的值/方法
provide('theme', theme);
provide('toggleTheme', toggleTheme);
</script>
2.中間組件:無需操作 (Middle.vue)
中間組件不需要顯式接收 theme,直接透傳即可
3.后代組件:注入并使用 (DeepChild.vue)
<template>
<div class="descendant">
<h3>深層子組件</h3>
<p>接收到的主題:{{ theme }}</p>
<button @click="toggleTheme">切換主題</button>
</div>
</template>
<script setup lang="ts">
import { inject } from 'vue';
// 使用 inject 獲取,第二個參數(shù)為默認(rèn)值(可選)
const theme = inject('theme');
const toggleTheme = inject<() => void>('toggleTheme');
</script>
四、 集中式狀態(tài)管理:Vuex 與 Pinia
當(dāng)應(yīng)用變得龐大,組件間的關(guān)系交織成網(wǎng)時,我們需要一個“單一事實來源”。
Vuex:Vue 2 時代的標(biāo)準(zhǔn)?;?Mutation(同步)和 Action(異步)。
Pinia:Vue 3 的官方推薦。
- 優(yōu)勢:更完美的 TS 支持、沒有 Mutation 的繁瑣邏輯、極其輕量。
- 核心:
state、getters、actions。
Pinia 示例:
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
name: '張三',
age: 18
}),
actions: {
updateName(newName: string) {
this.name = newName;
}
}
});
五、 總結(jié)
安全性建議:在使用 defineExpose 時,盡量只暴露必要的接口,遵循最小暴露原則。
EventBus 警示:Vue 3 開發(fā)者請注意,不要再嘗試使用 new Vue() 來做事件總線,應(yīng)當(dāng)轉(zhuǎn)向 Pinia 或全局狀態(tài)。
以上就是Vue開發(fā)之組件通信的常用方案全攻略的詳細(xì)內(nèi)容,更多關(guān)于Vue組件通信的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue中的<template>標(biāo)簽與react中的<></>標(biāo)簽區(qū)別詳解
這篇文章主要為大家介紹了vue中的<template>標(biāo)簽與react中的<></>標(biāo)簽區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08

