【干貨】Vue3 組件通信方式詳解
前言
毫無疑問,組件通信是Vue中非常重要的技術之一,它的出現能夠使我們非常方便的在不同組件之間進行數據的傳遞,以達到數據交互的效果。所以,學習組件通信技術是非常有必要的,本文將總結Vue中關于組件通信的八種方式,幫助大家在使用Vue的過程中更加得心應手!
如果文中有不對、疑惑的地方,歡迎在評論區留言指正!!
一、什么是組件通信
在開始之前我們需要明白什么是組件通信,組件通信可以拆分為兩個部分:
- 組件
- 通信
都知道組件是vue最強大的功能之一,vue中每一個.vue文件我們都可以視之為一個組件,簡單來說組件就是對UI結構的復用。
通信指的是發送者通過某種媒體以某種格式來傳遞信息到收信者以達到某個目的。廣義上,任何信息的交通都是通信。而組件間通信即指組件(.vue)通過某種方式來傳遞信息以達到某個目的,舉個栗子我們在使用UI框架中的table組件,可能會往table組件中傳入某些數據,這個本質就形成了組件之間的通信
二、為什么要進行組件通信
通信的本質是信息同步,共享。回到vue中,每個組件之間的都有獨自的作用域,組件間的數據是無法共享的但實際開發工作中我們常常需要讓組件之間共享數據,這也是組件通信的目的要讓它們互相之間能進行通訊,這樣才能實現數據間的交互,完成某種功能的開發。
三、組件通信的分類
組件間通信的分類可以分成以下
- 父子組件之間的通信
- 兄弟組件之間的通信
- 祖孫與后代組件之間的通信
- 非關系組件間之間的通信
他們之間的關系如下圖:

目前最常用是props/$emit 和 vuex/pinia ,接下來是 provide/inject,其他不建議使用;
實際項目中,簡單父子組件傳遞采用props/$emit ,涉及全局共享的數據一般采用 vuex/pinia 結合存儲對象localStorage/sessionStorage使用。

四、Vue3 的八種組件通信方式
- props
- $emit
- expose / ref
- $attrs
- v-model
- provide / inject
- Vuex
- mitt
五、Vue3 八種通信方式用法講解
1. props
用 props 傳數據給子組件有兩種方法,如下
方法一,setup() 方法寫法
// Parent.vue 傳送
<child :msg1="msg1" :msg2="msg2"></child>
<script>
import child from "./child.vue"
import { ref, reactive } from "vue"
export default {
data(){
return {
msg1:"這是傳級子組件的信息1"
}
},
setup(){
// 創建一個響應式數據
// 寫法一 適用于基礎類型 ref 還有其他用處,下面章節有介紹
const msg2 = ref("這是傳級子組件的信息2")
// 寫法二 適用于復雜類型,如數組、對象
const msg2 = reactive(["這是傳級子組件的信息2"])
return {
msg2
}
}
}
</script>
// Child.vue 接收
<script>
export default {
props: ["msg1", "msg2"],// 如果這行不寫,下面就接收不到
setup(props) {
console.log(props) // { msg1:"這是傳給子組件的信息1", msg2:"這是傳給子組件的信息2" }
},
}
</script>
方法二,setup 語法糖
// Parent.vue 傳送
<child :msg2="msg2"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const msg2 = ref("這是傳給子組件的信息2")
// 或者復雜類型
const msg2 = reactive(["這是傳級子組件的信息2"])
</script>
// Child.vue 接收
<script setup>
// 不需要引入 直接使用
// import { defineProps } from "vue"
const props = defineProps({
// 寫法一
msg2: String
// 寫法二
msg2:{
type:String,
default:""
}
})
console.log(props) // { msg2:"這是傳級子組件的信息2" }
</script>
注意:
如果父組件是setup(),子組件setup 語法糖寫法的話,是接收不到父組件里 data 的屬性,只能接收到父組件里 setup 函數里傳的屬性。
如果父組件是setup 語法糖寫法,子組件setup()方法寫法,可以通過 props 接收到 data 和 setup 函數里的屬性,但是子組件要是在 setup 里接收,同樣只能接收到父組件中 setup 函數里的屬性,接收不到 data 里的屬性
官方也說了,既然用了 3,就不要寫 2 了,所以不推薦setup()方法寫法。下面的例子,一律只用語法糖的寫法。
2. $emit
// Child.vue 派發
<template>
// 寫法一
<button @click="emit('myClick')">按鈕</buttom>
// 寫法二
<button @click="handleClick">按鈕</buttom>
</template>
<script setup>
// 方法一 適用于Vue3.2版本 不需要引入
// import { defineEmits } from "vue"
// 對應寫法一
const emit = defineEmits(["myClick","myClick2"])
// 對應寫法二
const handleClick = ()=>{
emit("myClick", "這是發送給父組件的信息")
}
// 方法二 不適用于 Vue3.2版本,該版本 useContext()已廢棄
import { useContext } from "vue"
const { emit } = useContext()
const handleClick = ()=>{
emit("myClick", "這是發送給父組件的信息")
}
</script>
// Parent.vue 響應
<template>
<child @myClick="onMyClick"></child>
</template>
<script setup>
import child from "./child.vue"
const onMyClick = (msg) => {
console.log(msg) // 這是父組件收到的信息
}
</script>
3. expose / ref
父組件獲取子組件的屬性或者調用子組件方法。
// Child.vue
<script setup>
// 方法一 不適用于Vue3.2版本,該版本 useContext()已廢棄
import { useContext } from "vue"
const ctx = useContext()
// 對外暴露屬性方法等都可以
ctx.expose({
childName: "這是子組件的屬性",
someMethod(){
console.log("這是子組件的方法")
}
})
// 方法二 適用于Vue3.2版本, 不需要引入
// import { defineExpose } from "vue"
defineExpose({
childName: "這是子組件的屬性",
someMethod(){
console.log("這是子組件的方法")
}
})
</script>
// Parent.vue 注意 ref="comp"
<template>
<child ref="comp"></child>
<button @click="handlerClick">按鈕</button>
</template>
<script setup>
import child from "./child.vue"
import { ref } from "vue"
const comp = ref(null)
const handlerClick = () => {
console.log(comp.value.childName) // 獲取子組件對外暴露的屬性
comp.value.someMethod() // 調用子組件對外暴露的方法
}
</script>
4. attrs
attrs:包含父作用域里除 class 和 style 除外的非 props 屬性集合。
// Parent.vue 傳送
<child :msg1="msg1" :msg2="msg2" title="3333"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const msg1 = ref("1111")
const msg2 = ref("2222")
</script>
// Child.vue 接收
<script setup>
import { defineProps, useContext, useAttrs } from "vue"
// 3.2版本不需要引入 defineProps,直接用
const props = defineProps({
msg1: String
})
// 方法一 不適用于 Vue3.2版本,該版本 useContext()已廢棄
const ctx = useContext()
// 如果沒有用 props 接收 msg1 的話就是 { msg1: "1111", msg2:"2222", title: "3333" }
console.log(ctx.attrs) // { msg2:"2222", title: "3333" }
// 方法二 適用于 Vue3.2版本
const attrs = useAttrs()
console.log(attrs) // { msg2:"2222", title: "3333" }
</script>
5. v-model
可以支持多個數據雙向綁定
// Parent.vue
<child v-model:key="key" v-model:value="value"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const key = ref("1111")
const value = ref("2222")
</script>
// Child.vue
<template>
<button @click="handlerClick">按鈕</button>
</template>
<script setup>
// 方法一 不適用于 Vue3.2版本,該版本 useContext()已廢棄
import { useContext } from "vue"
const { emit } = useContext()
// 方法二 適用于 Vue3.2版本,不需要引入
// import { defineEmits } from "vue"
const emit = defineEmits(["key","value"])
// 用法
const handlerClick = () => {
emit("update:key", "新的key")
emit("update:value", "新的value")
}
</script>
6. provide / inject
provide / inject 為依賴注入
provide:可以讓我們指定想要提供給后代組件的數據或
inject:在任何后代組件中接收想要添加在這個組件上的數據,不管組件嵌套多深都可以直接拿來用
// Parent.vue
<script setup>
import { provide } from "vue"
provide("name", "RDIF")
</script>
// Child.vue
<script setup>
import { inject } from "vue"
const name = inject("name")
console.log(name) // RDIF
</script>
7. Vuex
// store/index.js
import { createStore } from "vuex"
export default createStore({
state:{ count: 1 },
getters:{
getCount: state => state.count
},
mutations:{
add(state){
state.count++
}
}
})
// main.js
import { createApp } from "vue"
import App from "./App.vue"
import store from "./store"
createApp(App).use(store).mount("#app")
// Page.vue
// 方法一 直接使用
<template>
<div>{{ $store.state.count }}</div>
<button @click="$store.commit('add')">按鈕</button>
</template>
// 方法二 獲取
<script setup>
import { useStore, computed } from "vuex"
const store = useStore()
console.log(store.state.count) // 1
const count = computed(()=>store.state.count) // 響應式,會隨著vuex數據改變而改變
console.log(count) // 1
</script>
8. mitt
Vue3 中沒有了 EventBus 跨組件通信,但是現在有了一個替代的方案 mitt.js,原理還是 EventBus。
先安裝 npm i mitt -S
然后像以前封裝 bus 一樣,封裝一下
mitt.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt
然后兩個組件之間通信的使用
// 組件 A
<script setup>
import mitt from './mitt'
const handleClick = () => {
mitt.emit('handleChange')
}
</script>
// 組件 B
<script setup>
import mitt from './mitt'
import { onUnmounted } from 'vue'
const someMethed = () => { ... }
mitt.on('handleChange',someMethed)
onUnmounted(()=>{
mitt.off('handleChange',someMethed)
})
</script>
六、參考資料
vue.js: https://cn.vuejs.org/
vuex是什么:https://vuex.vuejs.org/zh/
工作中要使用Git,看這篇文章就夠了:http://www.guosisoft.com/article/detail/410508049313861
企業數字化轉型如何做?看過來:http://www.guosisoft.com/article/detail/408745545576517
Vue2.x 組件通信方式:http://www.guosisoft.com/article/detail/411234710110277
【保姆級教程】Vue項目調試技巧:http://www.guosisoft.com/article/detail/430312211521605
Vue 前端開發團隊風格指南(史上最全):http://www.guosisoft.com/article/detail/415491255230533
國思RDIF低代碼快速開發平臺(支持vue2、vue3):http://www.guosisoft.com/article/detail/557095625134149
七、結語
如果本文對你有一點點幫助,點個贊支持一下吧,你的每一個【贊】都是我創作的最大動力 _
更多技術文章請往:
http://www.guosisoft.com/article
http://www.rdiframework.net/article
大家一起共同交流和進步呀!!
作者:
RDIF
出處:
http://www.rzrgm.cn/huyong/
Email:
406590790@qq.com
QQ:
406590790
微信:
13005007127(同手機號)
框架官網:
http://www.guosisoft.com/
http://www.rdiframework.net/
框架其他博客:
http://blog.csdn.net/chinahuyong
http://www.rzrgm.cn/huyong
國思RDIF開發框架
,
給用戶和開發者最佳的.Net框架平臺方案,為企業快速構建跨平臺、企業級的應用提供強大支持。
關于作者:系統架構師、信息系統項目管理師、DBA。專注于微軟平臺項目架構、管理和企業解決方案,多年項目開發與管理經驗,曾多次組織并開發多個大型項目,在面向對象、面向服務以及數據庫領域有一定的造詣。現主要從事基于
RDIF
框架的技術開發、咨詢工作,主要服務于金融、醫療衛生、鐵路、電信、物流、物聯網、制造、零售等行業。
如有問題或建議,請多多賜教!
本文版權歸作者和CNBLOGS博客共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,如有問題,可以通過微信、郵箱、QQ等聯系我,非常感謝。

毫無疑問,組件通信是Vue中非常重要的技術之一,它的出現能夠使我們非常方便的在不同組件之間進行數據的傳遞,以達到數據交互的效果。所以,學習組件通信技術是非常有必要的,本文將總結Vue中關于組件通信的八種方式,幫助大家在使用Vue的過程中更加得心應手!
如果文中有不對、疑惑的地方,歡迎在評論區留言指正!!
浙公網安備 33010602011771號