Vue常見組件間通信方案及典型應(yīng)用場(chǎng)景詳解
什么是組件通信
所謂組件通信,就是組件之間的數(shù)據(jù)交互,也就是把一個(gè)組件A里面的數(shù)據(jù)傳遞到另一個(gè)組件B,并能夠讓組件B根據(jù)這個(gè)數(shù)據(jù)更新界面。
在 Vue中,可用的通信方案有很多,下面給大家描述幾個(gè)常用的組件通信方案及其典型的應(yīng)用場(chǎng)景。
1、父子組件通信場(chǎng)景
父子組件通信是最典型的組件通信場(chǎng)景,沒有之一,他們之間通信主要使用自定義屬性或者ref。
第一種是自定義屬性,使用較為廣泛,在子組件中使用 props 選項(xiàng)進(jìn)行接收,子組件向父組件回傳數(shù)據(jù),使用自定義事件,在子組件中使用 $emit() 方法觸發(fā)執(zhí)行,并回傳數(shù)據(jù)給父組件。
// 定義組件h1-box Vue.component("h1-box", { // 通過(guò)props設(shè)置自定義屬性title接收組件外傳值 props: ["title"], // 通過(guò)emits設(shè)置自定義事件向外部發(fā)送事件 emits: ['give'], methods:{ clickHandler(){ // 通過(guò)$emit() 方法觸發(fā)執(zhí)行把當(dāng)前組件數(shù)據(jù)帶出去 this.$emit('give',{name:'lucy'}) } }, mounted() { // 通過(guò)this.title可以獲取外部傳入組件的值 console.log(this.title); }, });
第二種使用 ref 實(shí)現(xiàn)通信。我們知道,使用 ref 可以快速訪問一個(gè)組件實(shí)例對(duì)象及其內(nèi)部的數(shù)據(jù)和方法。這樣的話,在父組件中借助 refs可以訪問子級(jí)組件的數(shù)據(jù),還可以借助refs 可以訪問子級(jí)組件的數(shù)據(jù),還可以借助 refs可以訪問子級(jí)組件的數(shù)據(jù),還可以借助refs 調(diào)用子級(jí)組件中的方法,并傳遞事件參數(shù)給子級(jí)組件。當(dāng)然需要注意的是,在 Vue開發(fā)中,應(yīng)該盡量減少對(duì) ref 的使用。
<div id="app"> <!-- 組件 --> <son ref="son"></son> </div> new Vue({ el: "#app", mounted() { // 獲取到組件實(shí)例,就可以任意操作組件實(shí)例 console.log(this.$refs.son); let vm2 = this.$refs.son; // 修改son組件的響應(yīng)式數(shù)據(jù)msg vm2.msg = "sz2111"; // 調(diào)用son組件的changeMsg方法 vm2.changeMsg("sz2116"); }, components: { // 定義組件son son: { data() { return { msg: "sz2114", }; }, methods: { changeMsg(val) { this.msg = val; }, }, template: `<h1>hello world</h1>`, }, }, });
2、兄弟組件通信場(chǎng)景
這種場(chǎng)景使用狀態(tài)提升,這個(gè)概念源自 React 中的狀態(tài)提升思想。
所謂狀態(tài)提升,就是當(dāng)兩個(gè)組件希望共享一個(gè)數(shù)據(jù)時(shí),我們可以找到這兩個(gè)組件最近的父級(jí)組件,把這個(gè)要被共享的變量定義在最近的父組件中去,再通過(guò) props 向下傳遞給子組件們。需要注意的是,狀態(tài)提升適合應(yīng)用在簡(jiǎn)單的兄弟組件之間通信。當(dāng)遇到較為復(fù)雜的組件關(guān)系時(shí),使用狀態(tài)提升就顯得麻煩了。
上圖圖中如果想點(diǎn)擊Font按鈕改變主題字體大小,也就是Title和Font兩個(gè)組件字體大小都改變。
如果Title和Font組件都維護(hù)自己組件的狀態(tài)數(shù)據(jù)就不太好傳遞數(shù)據(jù),就可以他他們的狀態(tài)存儲(chǔ)到共同的父組件狀態(tài)中,也就是狀態(tài)提升。
<!-- 父組件app --> <div id="app"> <!-- 子組件font --> <font :font="fontSize"></font> <!-- 子組件title --> <title :font="fontSize"></title> </div> // 父組件 new Vue({ el:'#app', data:{ // 把子組件共同需要的數(shù)據(jù)存儲(chǔ)在共同的父組件上 fontSize:12 } }) // 子組件 Vue.component('font',{ // 通過(guò)自定義屬性接受父組件傳入的值 props:['font'], template:`<div :style="{fontSize:font+'px'}">hello</div>` }) // 子組件 Vue.component('title',{ // 通過(guò)自定義屬性接受父組件傳入的值 props:['font'], template:`<div :style="{fontSize:font+'px'}">world</div>` })
3、根組件和后代組件通信場(chǎng)景
這種場(chǎng)景主要是provide/inject。使用 provide 選項(xiàng),可以在任意組件中注入數(shù)據(jù);使用 inject 選項(xiàng),可以在后代組件中接受父級(jí)組件注入的數(shù)據(jù)。需要注意的是,provide/inject 這種通信方案是沒有響應(yīng)式的,即父組件注入的數(shù)據(jù)發(fā)生變化時(shí),后代組件不會(huì)自動(dòng)更新
上圖在祖先組件通過(guò)provide傳入的數(shù)據(jù),在后代的所有組件中都可以通過(guò)inject獲取到。
下面是一個(gè)通過(guò)provide/inject傳值的例子
<div id="app"> <three></three> </div>
// 根組件 new Vue({ el: "#app", // provide用于在一個(gè)vue實(shí)例里面給后面的子孫實(shí)例傳遞數(shù)據(jù) provide: function () { return { a: 100, c: 300, d: this.obj, }; } }); // 定義組件one Vue.component("one", { // inject用于在子孫組件中接收祖先通過(guò)provide傳入的變量c inject: ["a"], template: ` <div> <h1>我是one組件---{{a}}</h1> </div> `, }); // 定義組件two,里面有子組件one Vue.component("two", { // inject用于在子孫組件中接收祖先通過(guò)provide傳入的變量c,并重名成myC inject: { myC: "c", }, template: ` <div> <h1>我是two組件---{{myC}}</h1> <one></one> </div> `, }); // 定義組件three,里面有子組件two Vue.component("three", { // inject用于在子孫組件中接收祖先通過(guò)provide傳入的變量b,并重名成bbb,同時(shí)設(shè)置默認(rèn)值299999 inject: { bbb: { from: "b", default: 299999, }, }, template: ` <div> <h1>我是three組件---{{bbb}}</h1> <two></two> </div> `, });
4、插槽通信場(chǎng)景
在封裝組件時(shí),可以為 組件添加自定義屬性。使用這個(gè)組件時(shí),在父級(jí)組件中使用 #slotName='scope' 指令可以接收到子組件插槽傳遞過(guò)來(lái)的數(shù)據(jù)。ElementUI 中的 Table 表格、VantUI 中的 Tabbar 組件,都用到了插槽通信。
<div id="app"> <child> <template #abc> <h1>sz2114</h1> <h2>sz2115</h2> <h3>sz2116</h3> </template> <template #cindy> <h1>sz2014</h1> <h2>sz2015</h2> <h3>sz2016</h3> </template> </child> </div> // 全局組件 Vue.component("child", { template: ` <div> <slot name='cindy'></slot> <h1>hello world</h1> <slot name='abc'></slot> </div> `, }); let vm = new Vue({ el: "#app", });
5 無(wú)直接關(guān)系的組件通信場(chǎng)景
在沒有直接關(guān)聯(lián)的組件之間通信可以使用事件總線。事件總線是一種基于訂閱發(fā)布模式而設(shè)計(jì)的通信方案,在任意組件中訂閱指定“頻道”后,都能收到該“頻道”上的消息
。事件總線,它的強(qiáng)大之處在于:它是一種“一對(duì)多”的通信方案,還是一種“多頻道”的通信方案,非常強(qiáng)大。
<div id="app"> <input type="text" v-model="duanxin1" /> <button @click="clickHandler">給老師發(fā)消息</button> </div> // 中央事件總線: 類似一個(gè)事件對(duì)象 // 就像一個(gè)電信局 var bus = new Vue(); // 每個(gè)人就收短信都需要一個(gè)號(hào)碼 (事件名) // 想要接收短信要先去電信辦個(gè)卡 -- 注冊(cè)一個(gè)號(hào)碼 bus.$on("cyrevent", function (data) { console.log("短信內(nèi)容是"); console.log(data); }); new Vue({ el: "#app", data() { return { duanxin1: "", }; }, methods: { clickHandler() { // 別人想給我發(fā)消息 bus.$emit("cyrevent", this.duanxin1); }, }, });
6 大型項(xiàng)目中的復(fù)雜組件通信場(chǎng)景 - Vuex狀態(tài)管理
Vuex狀態(tài)管理是借助狀態(tài)管理工具,可以實(shí)現(xiàn)任意組件之間的數(shù)據(jù)通信。Vuex 提供了 state、mutations 等接口,可以方便地實(shí)現(xiàn)任意未知關(guān)系的組件之間的數(shù)據(jù)交互。因此,我們經(jīng)常稱 Vuex是 Vue開發(fā)中的終極通信方案。終極的意思,不是說(shuō)它可以隨意地替代其它通信方案,而是說(shuō) Vuex很好用,能夠清晰地管理數(shù)據(jù)流。
上圖是vuex官方網(wǎng)站的工作流程圖,特別形象。
7 其他的一些組件通信方案
上面說(shuō)到的是比較常用的組件通信方式,還有一些方式是上面通信方法不能使用的替代手段。
第一個(gè)是: $parent/$children
,借助這兩個(gè) API,可以實(shí)現(xiàn)在組件樹之間任意穿梭。我們?cè)诋?dāng)前組件的作用域中,可以訪問到任意其它組件的內(nèi)部數(shù)據(jù),并調(diào)用它的方法。因此,這也是一種可用的通信方案。
第二個(gè)是:$attrs/$listeners
。使用 $attrs
可以訪問到父組件傳遞過(guò)來(lái)的自定義屬性(除 class 和 style 外),使用 $listeners
可以訪問并調(diào)用父組件傳遞過(guò)來(lái)的自定義事件,通過(guò)對(duì)自定義事件的調(diào)用還能向父組件回傳數(shù)據(jù)。這兩個(gè)內(nèi)置 API,在某種程度上可以看成是父子組件通信的替代方案。
總結(jié)
雖然 Vue中可用的通信方案很多,但要注意的是“別濫用”。在同一個(gè)項(xiàng)目中,選擇適合場(chǎng)景的通信方案很重要,不要使用過(guò)多的通信方式,這會(huì)導(dǎo)致代碼很難維護(hù)。一個(gè)數(shù)據(jù)流不清晰的 Web應(yīng)用,通常是很難得到持續(xù)發(fā)展的。
以上就是Vue常見組件間通信方案及典型應(yīng)用場(chǎng)景詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue組件間通信應(yīng)用場(chǎng)景的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue3項(xiàng)目中引入html頁(yè)面的方法舉例
這篇文章主要給大家介紹了關(guān)于Vue3項(xiàng)目中引入html頁(yè)面的相關(guān)資料,Vue3是一個(gè)JavaScript框架,通常我們使用它來(lái)構(gòu)建單頁(yè)應(yīng)用程序(SPA),如果你想在HTML頁(yè)面中使用Vue3,可以參考這篇文章,需要的朋友可以參考下2023-09-09Vue項(xiàng)目打包部署到apache服務(wù)器的方法步驟
這篇文章主要介紹了Vue項(xiàng)目打包部署到apache服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Vue是怎么渲染template內(nèi)的標(biāo)簽內(nèi)容的
這篇文章主要介紹了Vue是怎么渲染template內(nèi)的標(biāo)簽內(nèi)容的,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06詳解基于vue-router的動(dòng)態(tài)權(quán)限控制實(shí)現(xiàn)方案
本篇文章主要介紹了詳解基于vue-router的動(dòng)態(tài)權(quán)限實(shí)現(xiàn)方案,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09vue element ui validate 主動(dòng)觸發(fā)錯(cuò)誤提示操作
這篇文章主要介紹了vue element ui validate 主動(dòng)觸發(fā)錯(cuò)誤提示操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09詳解VUE里子組件如何獲取父組件動(dòng)態(tài)變化的值
這篇文章主要介紹了詳解VUE里子組件如何獲取父組件動(dòng)態(tài)變化的值,子組件通過(guò)props獲取父組件傳過(guò)來(lái)的數(shù)據(jù),子組件存在操作傳過(guò)來(lái)的數(shù)據(jù)并且傳遞給父組件,需要的朋友可以參考下2018-12-12vue + element動(dòng)態(tài)多表頭與動(dòng)態(tài)插槽
這篇文章主要介紹了vue + element動(dòng)態(tài)多表頭與動(dòng)態(tài)插槽,下面文章圍繞vue + element動(dòng)態(tài)多表頭與動(dòng)態(tài)插槽的相關(guān)資料展開文章的內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考一下,希望對(duì)大家有所幫助2021-12-12