VUE組件間通信

vue是數(shù)據(jù)驅(qū)動(dòng)視圖更新的框架狐蜕,所以對于vue來說組件間的數(shù)據(jù)通信非常重要。組件是vue的強(qiáng)大功能之一卸夕,而組件間的作用域是互相獨(dú)立的层释,這就意味著組件間的數(shù)據(jù)無法互相引用,那么組件間如何通信便成為了重點(diǎn)知識(shí)快集。本文將分析不同組件間通信的各種方式贡羔。

prop/ $emit

父組件通過prop向子組件傳遞數(shù)據(jù)廉白,而子組件通過$emit向父組件通信

//父組件
<template>
    <Child :text=text @change="changeCurrentText"></Child>
</template>
<script>
import Child from './child.vue'
export default {
    data(){
        return{
            text: 'sss'
        }
    },
    components:{ Child },
    methods: {
        changeCurrentText(value){
            this.text = value
        }
    }
}
</script>
//child.vue
<template>
    <div @click="changeText">
        {{text}}
      </div>
</template>
<script>
export default {
    props:{
        text: {
            type: String
        }
    },
    methods:{
        changeText(){
            this.$emit('change','改變了')
        }
    }
}
</script>

父子組件之間的數(shù)據(jù)傳遞只能從父組件傳向子組件,這正是vue的單向數(shù)據(jù)流設(shè)計(jì)理念乖寒。而prop在其中充當(dāng)了數(shù)據(jù)傳遞的一個(gè)銜接口蒙秒,在子組件中我們可以在props中定義接收子組件值的類型和默認(rèn)值。
這種通信方式是父子通信最常用的宵统,傳值取值方便簡潔明了晕讲,但是這種方式的缺點(diǎn)是:

  1. 由于數(shù)據(jù)是單向傳遞,如果子組件需要改變父組件的props值每次需要給子組件綁定對應(yīng)的監(jiān)聽事件马澈。
  2. 如果父組件需要給孫組件傳值瓢省,需要子組件進(jìn)行轉(zhuǎn)發(fā)。
    注:組件中的數(shù)據(jù)共有三種形式:data痊班、props勤婚、computed

ref

ref被用來給元素或子組件注冊引用信息,引用信息將會(huì)注冊在父組件的$refs對象上涤伐,若注冊了多個(gè)ref引用馒胆,同樣都將會(huì)被注冊在父組件的$refs對象上,如果在普通的DOM元素上使用凝果,引用指向的就是DOM元素祝迂;如果用在子組件上,引用就指向組件實(shí)例器净。然后通過$refs可以獲得你綁定的這個(gè)組件或者元素的一些相關(guān)信息型雳,還可以修改子組件的值。

//父組件:
<template>
    <div>
        <Child ref="a" />
        <input type="button" @click="fn">
    </div>
</template>
<script>
import Child from "./Child"
export default{
    methods:{
        fn(){
            this.$refs["a"].sun=10
            console.log(this.$refs["a"].sun)//10
        }
    },
    components:{
        Child
    },
    mounted(){
        console.log(this.$refs["a"].sun)//1
    }
}
</script>
//子組件:
<template>
    <div>
        子組件
    </div>
</template>
<script>
export default{
    data(){
        return{
            sun:1
        }
    }
}
</script>

$attrs/ $listeners

多級(jí)組件嵌套時(shí)可使用
$attrs: 只代表沒有被聲明未props的屬性山害,如果某個(gè)屬性已存在于子組件的props中則$attrs會(huì)將該屬性剔除纠俭,$attrs是組件標(biāo)簽上的靜態(tài)屬性值(attr)和動(dòng)態(tài)屬性值(:attr)的對象集合。

//父組件A
<template>
  <B :name='name' :age='age'/>
</template>
import B from './B.vue'
export default {
     data() {
        return {
          name:"小紅",
          age:"18"
        }
     },
     components:{ B },
   }
//子組件B
<template>
  <div>
    <div>{{name}}</div>
    <div>{{$attrs.age}}</div>
    //通過v-bind 綁定$attrs屬性浪慌,C組件可以直接獲取到A組件中傳遞下來的props(除了B組件中props聲明的)
     <C v-bind="$attrs" v-on="$listeners"/>
 </div>
</template>
import C from './C.vue'
export default {
    props:["name"]
     data() {
        return { }
     },
     components:{ C },
   }
//孫組件C
<template>
      <div>age:{{$attrs.age}}</div>
</template>
<script>
export default {
}
</script>

$listeners 包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器冤荆,它可以通過 v-on=”$listeners” 傳入內(nèi)部組件。

//父組件A
<template>
  <B :name='name' :age='age' v-on:testB="onB" v-on:testC="onC" />
</template>
import B from './B.vue'
export default {
     data() {
        return {
          name:"小紅",
          age:"18"
        }
     },
     components:{ B },
methods: {
         //b組件傳回來的數(shù)據(jù)
        onB(msg) {
            console.log('我是B:',msg);
        },

        // c組件傳回來的數(shù)據(jù)
        onC(msg) {
            console.log('我是C:',msg);
        }
    }
   }
//子組件B
<template>
  <div>
    <div>{{name}}</div>
 //C組件中能直接觸發(fā)test的原因在于 B組件調(diào)用C組件時(shí) 使用 v-on 綁定了$listeners 屬性 
     <C v-bind="$attrs" v-on="$listeners"/>
 </div>
</template>
import C from './C.vue'
export default {
    props:["name"]
     data() {
        return { }
     },
     components:{ C },
mounted() {
        this.$emit('testB','BBBB');
    }
   }
//孫組件C
<template>
      <div>age:{{$attrs.age}}</div>
</template>
<script>
export default {
mounted() {
        this.$emit('testC','CCCC');
    }
}
</script>

簡單來說:$attrs與$listeners 是兩個(gè)對象权纤,$attrs 里存放的是父組件中綁定的非 Props 屬性钓简,$listeners里存放的是父組件中綁定的非原生事件。

provide/ inject

provide 和 inject 綁定并不是可響應(yīng)的妖碉,如果你傳入了一個(gè)可監(jiān)聽的對象涌庭,那么其對象的屬性還是可響應(yīng)的。
provide 可以在祖先組件中指定我們想要提供給后代組件的數(shù)據(jù)或方法欧宜,而在任何后代組件中坐榆,我們都可以使用 inject 來接收 provide 提供的數(shù)據(jù)或方法。

// 父組件
<template>
  <div>
    <div>{{foo}}</div>
    <B/>
  </div>
</template>

<script>
import B from "./B";
export default {
  components: { B },
  provide() {
    return {
      foo: this.foo
    };
  },
  data() {
    return {
      foo: "父組件",
    };
  }冗茸,
  mounted() {
    console.log(this.foo)
  },
};
</script>
//子級(jí)組件
<template>
  <C/>
</template>

<script>
import C from "./C";
export default {
  components: { C },
};
</script>
//孫級(jí)組件席镀,接收foo
<template>
  <div>{{foo}}</div>
</template>

<script>
export default {
  inject: ["foo"],
  mounted() {
    console.log(this.foo)
  },
};
</script>

將數(shù)據(jù)變成可響應(yīng)式的解決方案是把provide所在的Vue實(shí)例給傳遞下去匹中,再來改造一下

provide() {
    return {
      foo: this.foo
    };
  },
  data() {
    return {
      foo: {
        foo: "父組件"
      }

在這種情況下如果在孫組件改變inject中foo的值,也會(huì)響應(yīng)的更新到父組件中豪诲,當(dāng)然為了保護(hù)單向數(shù)據(jù)流機(jī)制顶捷,最佳實(shí)踐還是不要在子組件里更改inject。
在進(jìn)行組件庫開發(fā)時(shí)provide/inject是一個(gè)不錯(cuò)的選擇屎篱,但是當(dāng)多個(gè)后代組件同時(shí)依賴同一個(gè)父組件提供數(shù)據(jù)時(shí)服赎,只要任一組件對數(shù)據(jù)進(jìn)行了修改,所有依賴的組件都會(huì)受到影響交播,實(shí)際上是增加了耦合度重虑;任意層級(jí)訪問使數(shù)據(jù)追蹤變的比較困難,你并不能準(zhǔn)確的定位到是哪一個(gè)層級(jí)對數(shù)據(jù)進(jìn)行了改變秦士,當(dāng)數(shù)據(jù)出現(xiàn)問題時(shí)缺厉,尤其是多人協(xié)作時(shí),可能會(huì)大大增加問題定位的損耗隧土。

EventBus

EventBus又稱事件總線提针,相當(dāng)于一個(gè)全局的倉庫,任何組件都可以去這個(gè)倉庫里獲取事件

const eventBus = new Vue();
eventBus.$emit(eventName, […args]) //發(fā)布事件
eventBus.$on(event, callback)      //訂閱事件
//實(shí)例如下:
// eventBus.js
import Vue from 'vue'
export const eventBus = new Vue();
//另外一種方式曹傀,可以直接在項(xiàng)目中的 main.js 初始化 EventBus(這種方式初始化的EventBus是一個(gè)全局的事件總線) :
Vue.prototype.$EventBus = new Vue()
//a.vue發(fā)送事件
<template>
    <button @click="sendMsg()">-</button>
</template>

<script> 
import { EventBus } from "../event-bus.js";
export default {
  methods: {
    sendMsg() {
      EventBus.$emit("aMsg", '來自A頁面的消息');
    }
  }
}; 
</script>

//b.vue接收事件
<template>
  <p>{{msg}}</p>
</template>

<script> 
import { 
  EventBus 
} from "../event-bus.js";
export default {
  data(){
    return {
      msg: ''
    }
  },
  mounted() {
    EventBus.$on("aMsg", (msg) => {
      // A發(fā)送來的消息
      this.msg = msg;
    });
  }
};
</script>

vue是單頁應(yīng)用辐脖,如果你在某一個(gè)頁面刷新了之后,與之相關(guān)的EventBus會(huì)被移除卖毁;如果是業(yè)務(wù)有反復(fù)操作的頁面揖曾,EventBus在監(jiān)聽的時(shí)候就會(huì)觸發(fā)很多次落萎,所以通常在vue頁面銷毀時(shí)亥啦,同時(shí)移除EventBus事件監(jiān)聽。

//移除事件監(jiān)聽
import { 
  eventBus 
} from './event-bus.js'
EventBus.$off('aMsg', {})

也可以使用 EventBus.$off('aMsg') 來移除應(yīng)用內(nèi)所有對此某個(gè)事件的監(jiān)聽
全局EventBus的工作原理是發(fā)布/訂閱方法练链,通常稱為 Pub/Sub 翔脱。

//創(chuàng)建全局EventBus
var EventBus = new Vue();
Object.defineProperties(Vue.prototype, {
  $bus: {
    get: function () {
      return EventBus
    }
  }
})

在這個(gè)特定的總線中使用兩個(gè)方法$on和$emit。一個(gè)用于創(chuàng)建發(fā)出的事件媒鼓,它就是$emit届吁;另一個(gè)用于訂閱$on:

var EventBus = new Vue();

this.$bus.$emit('nameOfEvent', { ... pass some event data ...});

this.$bus.$on('nameOfEvent',($event) => {
  // ...
})

然后我們可以在某個(gè)Vue頁面使用this.$bus.$emit("sendMsg", 'emit....');,另一個(gè)Vue頁面使用

this.$bus.$on('updateMessage', function(value) {
  console.log(value); // emit....
})

同時(shí)也可以使用this.$bus.$off('sendMsg')來移除事件監(jiān)聽绿鸣。

vuex

Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疚沐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子潮模,更是在濱河造成了極大的恐慌亮蛔,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擎厢,死亡現(xiàn)場離奇詭異究流,居然都是意外死亡辣吃,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門芬探,熙熙樓的掌柜王于貴愁眉苦臉地迎上來神得,“玉大人,你說我怎么就攤上這事偷仿×ú荆” “怎么了?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵酝静,是天一觀的道長卡骂。 經(jīng)常有香客問我,道長形入,這世上最難降的妖魔是什么全跨? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮亿遂,結(jié)果婚禮上浓若,老公的妹妹穿的比我還像新娘。我一直安慰自己蛇数,他們只是感情好挪钓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耳舅,像睡著了一般碌上。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浦徊,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天馏予,我揣著相機(jī)與錄音,去河邊找鬼盔性。 笑死霞丧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冕香。 我是一名探鬼主播蛹尝,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼悉尾!你這毒婦竟也來了突那?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬榮一對情侶失蹤构眯,失蹤者是張志新(化名)和其女友劉穎愕难,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡务漩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年拄衰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饵骨。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翘悉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出居触,到底是詐尸還是另有隱情妖混,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布轮洋,位于F島的核電站制市,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏弊予。R本人自食惡果不足惜祥楣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汉柒。 院中可真熱鬧误褪,春花似錦、人聲如沸碾褂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽正塌。三九已至嘀略,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乓诽,已是汗流浹背帜羊。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留问裕,地道東北人逮壁。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像粮宛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子卖宠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

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

  • 一巍杈、組件間通信的概念 開始之前,我們把組件間通信這個(gè)詞進(jìn)行拆分 組件 通信 都知道組件是vue最強(qiáng)大的功能之一扛伍,v...
    夢Sir閱讀 386評(píng)論 0 0
  • ????眾所周知筷畦,組件是 vue.js最強(qiáng)大的功能之一,而組件實(shí)例的作用域是相互獨(dú)立的,這就意味著不同組件之間的數(shù)...
    kjkongjun閱讀 440評(píng)論 0 1
  • 先創(chuàng)建一個(gè) vue 項(xiàng)目鳖宾,把不需要的刪掉吼砂,在components中新建文件 一、props 和 $emit 1.父...
    iCherries閱讀 295評(píng)論 1 3
  • 前言 組件是 vue.js最強(qiáng)大的功能之一鼎文,而組件實(shí)例的作用域是相互獨(dú)立的渔肩,這就意味著不同組件之間的數(shù)據(jù)無法相互引...
    用技術(shù)改變世界閱讀 2,164評(píng)論 1 3
  • 摘要: 總有一款合適的通信方式。 作者:浪里行舟 Fundebug經(jīng)授權(quán)轉(zhuǎn)載拇惋,版權(quán)歸原作者所有周偎。 前言 組件是 v...
    Fundebug閱讀 15,574評(píng)論 3 57