Vue2組件通信方式及其應(yīng)用場(chǎng)景

寫在最前:文章轉(zhuǎn)自掘金

一唯竹、prop & this.emit('Method name', value)

1. 優(yōu)點(diǎn)

父子組件通信方面靈活

2. 缺點(diǎn)

  • props 對(duì)父組件數(shù)據(jù)的篡改
  • 跨層級(jí)通信,兄弟組件通訊困難

3. 應(yīng)用場(chǎng)景

props的應(yīng)用場(chǎng)景很簡(jiǎn)單苦丁,就是正常的父子組件通信

二浸颓、this.$xxx

實(shí)際操作中會(huì)有很大的弊端,而且vue本身也不提倡這種通信方式。而且這種通信方式也有很多風(fēng)險(xiǎn)性产上。

三棵磷、provide inject

1. 基本用法

在父組件上通過(guò)provide將方法,屬性晋涣,或者是自身實(shí)例暴露出去仪媒,子孫組件,插槽組件,甚至是子孫組件的插槽組件谢鹊,通過(guò)inject把父輩provide引進(jìn)來(lái)算吩。
父組件:

<template>
  <div class="father" >
     <div>子組件對(duì)我說(shuō):{{  sonMes  }}</div>
     <div>孫組件對(duì)我說(shuō):{{  grandSonMes  }}</div>
     <son />
  </div>
</template>
<script>
import son from './son'
export default {
   name:'father',
   components:{
       son /* 子組件 */
   },
   provide(){
       return {
           /* 將自己暴露給子孫組件 ,這里聲明的名稱要于子組件引進(jìn)的名稱保持一致 */
           father:this
       }
   },
   data(){
       return {
          grandSonMes:'', /* 來(lái)自子組件的信息 */
          sonMes:''      /* 發(fā)送給子組件的信息  */
       } 
   },
   methods:{
      /* 接受孫組件信息 */
      grandSonSay(value){
          this.grandSonMes = value
      },
      /* 接受子組件信息 */ 
      sonSay(value){
          this.sonMes = value
      },
   },
}
</script>

這里我們通過(guò)provide把本身暴露出去。??????這里聲明的名稱要與子組件引進(jìn)的名稱保持一致
子組件

<template>
    <div class="son" >
        <input  v-model="mes"   /> <button @click="send"  >對(duì)父組件說(shuō)</button>
        <grandSon />
    </div> 
</template>

<script>
import  grandSon from './grandSon'
export default {
    /* 子組件 */
   name:'son',
   components:{
       grandSon /* 孫組件 */
   },
   data(){
       return {
           mes:''
       }
   },
   /* 引入父組件 */
   inject:['father'],
   methods:{
       send(){
           this.father.sonSay(this.mes)
       }
   },
    
}
</script>

子組件通過(guò)inject把父組件實(shí)例引進(jìn)來(lái)佃扼,然后可以直接通過(guò)this.father可以直接獲取到父組件赌莺,并調(diào)用下面的sonSay方法。
孫組件

<template>
   <div class="grandSon" >
        <input  v-model="mes"  /> <button @click="send"  >對(duì)爺爺組件說(shuō)</button>
    </div> 
</template>

<script>
export default {
    /* 孫組件 */
   name:'grandSon',
   /* 引入爺爺組件 */
   inject:['father'],
   data(){
       return {
           mes:''
       }
   },
   methods:{
       send(){
           this.father.grandSonSay( this.mes )
       }
   }
}
</script>

2. 插槽方式

provide , inject 同樣可以應(yīng)用在插槽上松嘶,我們給父子組件稍微變動(dòng)一下艘狭。
父組件

<template>
  <div class="father" >
     <div>子組件對(duì)我說(shuō):{{  sonMes  }}</div>
     <div>孫組件對(duì)我說(shuō):{{  grandSonMes  }}</div>
     <son >
         <grandSon/>
     </son>
  </div>
</template>
<script>
import son from './slotSon'

import grandSon from './grandSon' 
export default {
   name:'father',
   components:{
       son, /* 子組件 */
       grandSon /* 孫組件 */
   },
   provide(){
       return {
           /* 將自己暴露給子孫組件 */
           father:this
       }
   },
   data(){
       return {
          grandSonMes:'', /* 來(lái)自子組件的信息 */
          sonMes:''      /* 發(fā)送給子組件的信息  */
       } 
   },
   methods:{
      /* 接受孫組件信息 */
      grandSonSay(value){
          this.grandSonMes = value
      },
      /* 接受子組件信息 */ 
      sonSay(value){
          this.sonMes = value
      },
   },
}
</script>

子組件

<template>
    <div class="son" >
        <input  v-model="mes"   /> <button @click="send"  >對(duì)父組件說(shuō)</button>
        <slot />
    </div> 
</template>

達(dá)到了同樣的通信效果。實(shí)際這種插槽模式,所在都在父組件注冊(cè)的組件翠订,最后孫組件也會(huì)綁定到子組件的children下面巢音。和上述的情況差不多。

3. provied其他用法

provide不僅能把整個(gè)父組件全部暴露出去尽超,也能根據(jù)需要只暴露一部分(一些父組件的屬性或者是父組件的方法)官撼,上述的例子中,在子孫組件中似谁,只用到了父組件的方法傲绣,所以我們可以只提供兩個(gè)通信方法。但是這里注意的是巩踏,如果我們向外提供了方法,如果方法里面有操作this行為秃诵,需要綁定this
父組件

   provide(){
       return {
           /* 將通信方法暴露給子孫組件(注意綁定this) */
           grandSonSay:this.grandSonSay.bind(this),
           sonSay:this.sonSay.bind(this)
       }
   },   
   methods:{
      /* 接受孫組件信息 */
      grandSonSay(value){
          this.grandSonMes = value
      },
      /* 接受子組件信息 */ 
      sonSay(value){
          this.sonMes = value
      },
   },

子組件

/* 引入父組件方法 */
   inject:['sonSay'],
   methods:{
       send(){
           this.sonSay(this.mes)
       }
   },

4. 優(yōu)缺點(diǎn)

  • 組件通信不受到子組件層級(jí)的影響
  • 適用于插槽,嵌套插槽

  • 不適合兄弟通訊
  • 父級(jí)組件無(wú)法主動(dòng)通信

5. 應(yīng)用場(chǎng)景

provide-inject這種通信方式塞琼,更適合深層次的復(fù)雜的父子代通信菠净,子孫組件可以共享父組件的狀態(tài),還有一點(diǎn)就是適合el-form el-form-item這種插槽類型的情景彪杉。

四署穗、vuex

五秃嗜、事件總線一 EventBus

EventBus事件總線, EventBus 所有事件統(tǒng)一調(diào)度,有一個(gè)統(tǒng)一管理事件中心,一個(gè)組件綁定事件低飒,另一個(gè)組件觸發(fā)事件眼五,所有的組件通信不再收到父子組件的限制案腺,那個(gè)頁(yè)面需要數(shù)據(jù)日戈,就綁定事件另凌,然后由數(shù)據(jù)提供者觸發(fā)對(duì)應(yīng)的事件來(lái)提供數(shù)據(jù)。

EventBus 核心思想是事件的綁定和觸發(fā)残拐,這一點(diǎn)和vuethis.$emitthis.$on一樣途茫,這個(gè)也是整個(gè)EventBus核心思想。接下來(lái)我們來(lái)重點(diǎn)解析這個(gè)流程溪食。

1. 基本用法

EventBus

class EventBus {
    es = {}
     /* 綁定事件 */ 
    on(eventName, cb) {
        if (!this.es[eventName]) {
            this.es[eventName] = []
        }
        this.es[eventName].push({
            cb
        })
    }
    /* 觸發(fā)事件 */
    emit(eventName, ...params) {
        const listeners = this.es[eventName] || []
        let l = listeners.length

        for (let i = 0; i < l; i++) {
            const { cb } = listeners[i]
            cb.apply(this, params)
        }
    }
}

export default new EventBus()

這個(gè)就是一個(gè)簡(jiǎn)單的事件總線囊卜,有on,emit兩個(gè)方法

父組件

<template>
  <div class="father" >
     <input  v-model="mes"   /> <button @click="send"  >對(duì)子組件說(shuō)</button>
     <div>子組件對(duì)我說(shuō):{{  sonMes  }}</div>
     <son />
     <brotherSon />
  </div>
</template>
<script>
import son from './son'
import brotherSon from './brother'
import EventBus from './eventBus'
export default {
   name:'father',
   components:{
       son ,/* 子組件 */
       brotherSon, /* 子組件 */
   },
   data(){
       return {
          mes:'',
          sonMes:''/* 發(fā)送給子組件的信息  */
       } 
   },
   mounted(){
      /* 綁定事件 */
      EventBus.on('sonSay',this.sonSay)
   },
   methods:{
      /* 傳遞給子組件 */
      send(){
          EventBus.emit('fatherSay',this.mes)
      },
      /* 接受子組件信息 */ 
      sonSay(value){
          this.sonMes = value
      },
   },
}
</script>

我們?cè)诔跏蓟臅r(shí)候通過(guò)EventBuson方法綁定sonSay方法供給給子組件使用。向子組件傳遞信息的時(shí)候错沃,通過(guò)emit觸發(fā)子組件的綁定方法栅组,實(shí)現(xiàn)了父子通信。 接下來(lái)我們看一下子組件枢析。

子組件

<template>
    <div class="son" >
        <div> 父組件對(duì)我說(shuō):{{ fatherMes  }} </div>
        <input  v-model="mes"   /> <button @click="send"  >對(duì)父組件說(shuō)</button>
        <div>
            <input  v-model="brotherMes"   /> <button @click="sendBrother"  >對(duì)兄弟組件說(shuō)</button>
        </div>
    </div> 
</template>
<script>
import EventBus from './eventBus' 
export default {
   name:'son',
   data(){
       return {
           mes:'',
           brotherMes:'',
           fatherMes:''
       }
   },
   mounted(){
       /* 綁定事件 */
       EventBus.on('fatherSay',this.fatherSay)
   },
   methods:{
       /* 向父組件傳遞信息 */
       send(){
          EventBus.emit('sonSay',this.mes)
       },
       /* 向兄弟組件傳遞信息 */
       sendBrother(){
          EventBus.emit('brotherSay',this.brotherMes)
       },
       /* 父組件對(duì)我說(shuō) */
       fatherSay(value){
          this.fatherMes = value
       }
   },
    
}
</script>

和父組件的邏輯差不多玉掸,把需要接受數(shù)據(jù)的方法,通過(guò)EventBus綁定醒叁,通過(guò)觸發(fā)eventBus方法司浪,來(lái)向外部傳遞信息。我們還模擬了兄弟之間通信的場(chǎng)景把沼。我們建立一個(gè)兄弟組件啊易。

<template>
  <div class="son" > 兄弟組件對(duì)我說(shuō): {{ brotherMes  }} </div>
</template>

<script>

import EventBus from './eventBus'
export default {
   /* */
   name:'brother',
   data(){
       return {
          brotherMes:''
       }
   },
   mounted(){
       /* 綁定事件給兄弟組件 */
       EventBus.on('brotherSay',this.brotherSay)
   },
   methods:{
       brotherSay(value){
           this.brotherMes = value 
       }
   }

}
</script>

我們可以看到,兄弟組件處理邏輯和父子之間沒(méi)什么區(qū)別饮睬。


效果圖.gif

2. 優(yōu)缺點(diǎn)

  • 簡(jiǎn)單靈活租谈,父子兄弟通信不受限制。
  • 通信方式不受框架影響
  • 維護(hù)困難捆愁,容易引起連鎖問(wèn)題
  • 需要謹(jǐn)小慎微的命令規(guī)范
  • 不利于組件化開發(fā)

3. 應(yīng)用場(chǎng)景

實(shí)現(xiàn)總線這種方式更適合割去,微信小程序,和基于vue構(gòu)建的小程序昼丑,至于為什么呢呻逆,因?yàn)槲覀兌贾佬〕绦虿捎秒p線程模型(渲染層+邏輯層)(如下圖所示),渲染層作用就是小程序wxml渲染到我們的視線中矾克,而邏輯層就是我們寫的代碼邏輯页慷,在性能上,我們要知道在渲染層浪費(fèi)的性能要遠(yuǎn)大于邏輯層的代碼執(zhí)行性能開銷胁附,如果我們?cè)谛〕绦蚶锊捎猛ㄟ^(guò)props等傳遞方式,屬性是綁定在小程序標(biāo)簽里面的滓彰,所以勢(shì)必要重新渲染視圖層控妻。如果頁(yè)面結(jié)構(gòu)復(fù)雜,可能會(huì)造成卡頓等情況揭绑,所以我們通過(guò)eventBus可以繞過(guò)渲染層弓候,直接有邏輯層講數(shù)據(jù)進(jìn)行推送郎哭,節(jié)約了性能的開銷。

wallhaven-135750.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末菇存,一起剝皮案震驚了整個(gè)濱河市夸研,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌依鸥,老刑警劉巖亥至,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異贱迟,居然都是意外死亡姐扮,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門衣吠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)茶敏,“玉大人,你說(shuō)我怎么就攤上這事缚俏【” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵忧换,是天一觀的道長(zhǎng)恬惯。 經(jīng)常有香客問(wèn)我,道長(zhǎng)包雀,這世上最難降的妖魔是什么宿崭? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮才写,結(jié)果婚禮上葡兑,老公的妹妹穿的比我還像新娘。我一直安慰自己赞草,他們只是感情好讹堤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著厨疙,像睡著了一般洲守。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沾凄,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天梗醇,我揣著相機(jī)與錄音,去河邊找鬼撒蟀。 笑死叙谨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的保屯。 我是一名探鬼主播手负,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涤垫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了竟终?” 一聲冷哼從身側(cè)響起蝠猬,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎统捶,沒(méi)想到半個(gè)月后榆芦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘾境,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年歧杏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迷守。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡犬绒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兑凿,到底是詐尸還是另有隱情凯力,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布礼华,位于F島的核電站咐鹤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏圣絮。R本人自食惡果不足惜祈惶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扮匠。 院中可真熱鬧捧请,春花似錦、人聲如沸棒搜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)力麸。三九已至可款,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間克蚂,已是汗流浹背闺鲸。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留埃叭,地道東北人翠拣。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像游盲,于是被迫代替她去往敵國(guó)和親误墓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容