文末送書,趕緊來參加啦~
本篇文章是全部採用的 <script setup> 這種組合式API寫法,相對於選項式來說,組合式API這種寫法更加自由,具體可以參考Vue文檔[1]對兩種方式的描述。
本篇文章將介紹如下七種組件通信方式:
開始搞事情~
舉一個栗子俗話說的好,學習不寫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中的狀態管理工具,使用這兩個工具可以輕鬆實現組件通信,由於這兩個工具功能比較強大,這裡就不做展示了,具體可以查閱文檔
寫在最後本篇文章到這就結束了,總的來說比較簡單,沒有什麼複雜內容。
如果這篇文章對你來說有點作用,歡迎點讚、評論、收藏,避免在需要的時候找不到。
如果文中有錯誤,歡迎指正~
來自:一碗周
https://juejin.cn/post/7062740057018335245
送書活動
本書從Vue框架的基礎語法講起,逐步深入Vue進階實戰,並在最後配合項目實戰案例,重點演示Vue在項目開發中的一些應用。在系統地講解Vue的相關知識之餘,本書力圖使讀者更深入地理解Vue項目開發。
本書共分為11章,涵蓋的主要內容有前端技術的發展歷程、Vue基本介紹、Vue語法、Vue選項、Vue內置組件、Vue項目化、使用Vue開發電商類網站、使用Vue開發企業官網、使用Vue開發移動端資訊類網站、使用Vue開發工具類網站等。
本書內容通俗易懂,案例豐富,實用性強,特別適合Vue的初學者和從業人員閱讀,同時適合職業生涯遇到「瓶頸」的前端從業人員和其他編程愛好者閱讀。另外,本書也適合作為相關培訓機構的教材。
前端桃園聯合清華大學出版社為大家送上 5本《Vue.js從入門到項目實戰(升級版)》,祝大家好運!
參與方式:
留言參與,在評論區隨便聊聊在學習 Vue 路上的一些故事,或者對 Vue 的看法,或者有什麼話相對筆者說的,問的都可以參與。中間之後我會在留言裡回覆中獎結果,截止時間為:8 月 3 日 24 點。
溫馨提醒:留言、點讚、轉發三連中獎率更高哦!