
作者 | 一碗周
https://juejin.cn/post/7062740057018335245
本篇文章是全部採用的<script setup>這種組合式API寫法,相對於選項式來說,組合式API這種寫法更加自由,具體可以參考Vue文檔對兩種方式的描述。本篇文章將介紹如下七種組件通信方式:
開始搞事情~
舉一個栗子俗話說的好,學習不寫demo,那就是耍流氓~
本篇文章將圍繞下面這個demo,如下圖所示:

上圖中,列表和輸入框分別是父子組件,根據不同傳值方式,可能誰是父組件誰是子組件會有所調整。
Props方式Props方式是Vue中最常見的一種父傳子的一種方式,使用也比較簡單。
根據上面的demo,我們將數據以及對數據的操作定義在父組件,子組件僅做列表的一個渲染;
父組件代碼如下:
<template><!--子組件--><child-components:list="list"></child-components><!--父組件--><divclass="child-wrapinput-group"><inputv-model="value"type="text"class="form-control"placeholder="請輸入"/><divclass="input-group-append"><button@click="handleAdd"class="btnbtn-primary"type="button">添加</button></div></div></template><scriptsetup>import{ref}from'vue'importChildComponentsfrom'./child.vue'constlist=ref(['JavaScript','HTML','CSS'])constvalue=ref('')//add觸發後的事件處理函數consthandleAdd=()=>{list.value.push(value.value)value.value=''}</script>子組件只需要對父組件傳遞的值進行渲染即可,代碼如下:
<template><ulclass="parentlist-group"><liclass="list-group-item"v-for="iinprops.list":key="i">{{i}}</li></ul></template><scriptsetup>import{defineProps}from'vue'constprops=defineProps({list:{type:Array,default:()=>[],},})</script>emit方式emit方式也是Vue中最常見的組件通信方式,該方式用於子傳父;
根據上面的demo,我們將列表定義在父組件,子組件只需要傳遞添加的值即可。
子組件代碼如下:
<template><divclass="child-wrapinput-group"><inputv-model="value"type="text"class="form-control"placeholder="請輸入"/><divclass="input-group-append"><button@click="handleSubmit"class="btnbtn-primary"type="button">添加</button></div></div></template><scriptsetup>import{ref,defineEmits}from'vue'constvalue=ref('')constemits=defineEmits(['add'])consthandleSubmit=()=>{emits('add',value.value)value.value=''}</script>在子組件中點擊【添加】按鈕後,emit一個自定義事件,並將添加的值作為參數傳遞。
父組件代碼如下:
<template><!--父組件--><ulclass="parentlist-group"><liclass="list-group-item"v-for="iinlist":key="i">{{i}}</li></ul><!--子組件--><child-components@add="handleAdd"></child-components></template><scriptsetup>import{ref}from'vue'importChildComponentsfrom'./child.vue'constlist=ref(['JavaScript','HTML','CSS'])//add觸發後的事件處理函數consthandleAdd=value=>{list.value.push(value)}</script>在父組件中只需要監聽子組件自定義的事件,然後執行對應的添加操作。
v-model方式v-model是Vue中一個比較出色的語法糖,就比如下面這段代碼
<ChildComponentv-model:title="pageTitle"/>就是下面這段代碼的簡寫形式
<ChildComponent:title="pageTitle"@update:title="pageTitle=$event"/>v-model確實簡便了不少,現在我們就來看一下上面那個demo,如何用v-model實現。
子組件:
<template><divclass="child-wrapinput-group"><inputv-model="value"type="text"class="form-control"placeholder="請輸入"/><divclass="input-group-append"><button@click="handleAdd"class="btnbtn-primary"type="button">添加</button></div></div></template><scriptsetup>import{ref,defineEmits,defineProps}from'vue'constvalue=ref('')constprops=defineProps({list:{type:Array,default:()=>[],},})constemits=defineEmits(['update:list'])//添加操作consthandleAdd=()=>{constarr=props.listarr.push(value.value)emits('update:list',arr)value.value=''}</script>在子組件中我們首先定義props和emits,然後添加完成之後emit指定事件。
註:update:*是Vue中的固定寫法,*表示props中的某個屬性名。
父組件中使用就比較簡單,代碼如下:
<template><!--父組件--><ulclass="parentlist-group"><liclass="list-group-item"v-for="iinlist":key="i">{{i}}</li></ul><!--子組件--><child-componentsv-model:list="list"></child-components></template><scriptsetup>import{ref}from'vue'importChildComponentsfrom'./child.vue'constlist=ref(['JavaScript','HTML','CSS'])</script>refs方式在使用選項式API時,我們可以通過this.$refs.name的方式獲取指定元素或者組件,但是組合式API中就無法使用哪種方式獲取。如果我們想要通過ref的方式獲取組件或者元素,需要定義一個同名的Ref對象,在組件掛載後就可以訪問了。
示例代碼如下:
<template><ulclass="parentlist-group"><liclass="list-group-item"v-for="iinchildRefs?.list":key="i">{{i}}</li></ul><!--子組件ref的值與<script>中的保持一致--><child-componentsref="childRefs"></child-components><!--父組件--></template><scriptsetup>import{ref}from'vue'importChildComponentsfrom'./child.vue'constchildRefs=ref(null)</script>子組件代碼如下:
<template><divclass="child-wrapinput-group"><inputv-model="value"type="text"class="form-control"placeholder="請輸入"/><divclass="input-group-append"><button@click="handleAdd"class="btnbtn-primary"type="button">添加</button></div></div></template><scriptsetup>import{ref,defineExpose}from'vue'constlist=ref(['JavaScript','HTML','CSS'])constvalue=ref('')//add觸發後的事件處理函數consthandleAdd=()=>{list.value.push(value.value)value.value=''}defineExpose({list})</script>setup組件默認是關閉的,也即通過模板ref獲取到的組件的公開實例,不會暴露任何在<script setup>中聲明的綁定。如果需要公開需要通過defineExpose API暴露。
provide/inject方式provide和inject是Vue中提供的一對API,該API可以實現父組件向子組件傳遞數據,無論層級有多深,都可以通過這對API實現。示例代碼如下所示:
父組件
<template><!--子組件--><child-components></child-components><!--父組件--><divclass="child-wrapinput-group"><inputv-model="value"type="text"class="form-control"placeholder="請輸入"/><divclass="input-group-append"><button@click="handleAdd"class="btnbtn-primary"type="button">添加</button></div></div></template><scriptsetup>import{ref,provide}from'vue'importChildComponentsfrom'./child.vue'constlist=ref(['JavaScript','HTML','CSS'])constvalue=ref('')//向子組件提供數據provide('list',list.value)//add觸發後的事件處理函數consthandleAdd=()=>{list.value.push(value.value)value.value=''}</script>子組件
<template><ulclass="parentlist-group"><liclass="list-group-item"v-for="iinlist":key="i">{{i}}</li></ul></template><scriptsetup>import{inject}from'vue'//接受父組件提供的數據constlist=inject('list')</script>值得注意的是使用provide進行數據傳遞時,儘量readonly進行數據的包裝,避免子組件修改父級傳遞過去的數據。
事件總線Vue3中移除了事件總線,但是可以藉助於第三方工具來完成,Vue官方推薦mitt或tiny-emitter;
在大多數情況下不推薦使用全局事件總線的方式來實現組件通信,雖然比較簡單粗暴,但是長久來說維護事件總線是一個大難題,所以這裡就不展開講解了,具體可以閱讀具體工具的文檔。
狀態管理工具Vuex和Pinia是Vue3中的狀態管理工具,使用這兩個工具可以輕鬆實現組件通信,由於這兩個工具功能比較強大,這裡就不做展示了,具體可以查閱文檔。
寫在最後本篇文章到這就結束了,總的來說比較簡單,沒有什麼複雜內容。
如果這篇文章對你來說有點作用,歡迎點讚、評論、收藏,避免在需要的時候找不到。
如果文中有錯誤,歡迎指正~

每日分享前端插件乾貨,歡迎關注!
點讚和在看就是最大的支持❤️