vue組件的通信方式總結(jié)(8種)

  1. props和$emit
  2. 中央事件總線
  3. $attrs和$listeners
  4. provide和inject
  5. v-model
  6. $parent和$children
  7. boradcast和dispatch
  8. vuex

props和$emit

父組件向子組件傳遞數(shù)據(jù)是通過prop傳遞的稍刀,子組件傳遞數(shù)據(jù)給父組件是通過$emit觸發(fā)事件來做到的尊勿。

  1. 父組件傳遞了message數(shù)據(jù)給子組件碰辅,并且通過v-on綁定了一個getChildData事件來監(jiān)聽子組件的觸發(fā)事件;
  2. 子組件通過props得到相關(guān)的message數(shù)據(jù),最后通過this.$emit觸發(fā)了getChildData事件。
Vue.component('child',{
        data(){
            return {
                mymessage:this.message
            }
        },
        template:`
            <div>
                <input type="text" v-model="mymessage" @input="passData(mymessage)"> </div>
        `,
        props:['message'],//得到父組件傳遞過來的數(shù)據(jù)
        methods:{
            passData(val){
                //觸發(fā)父組件中的事件
                this.$emit('getChildData',val)
            }
        }
    })
    Vue.component('parent',{
        template:`
            <div>
                <p>this is parent compoent!</p>
                <child :message="message" v-on:getChildData="getChildData"></child>
            </div>
        `,
        data(){
            return {
                message:'hello'
            }
        },
        methods:{
            //執(zhí)行子組件觸發(fā)的事件
            getChildData(val){
                console.log(val)
            }
        }
    })
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })

中央事件總線

上面兩種方式處理的都是父子組件之間的數(shù)據(jù)傳遞,而如果兩個組件不是父子關(guān)系呢典挑?這種情況下可以使用中央事件總線的方式。新建一個Vue事件bus對象啦吧,然后通過bus.emit觸發(fā)事件您觉,bus.on監(jiān)聽觸發(fā)的事件。

Vue.component('brother1',{
        data(){
            return {
                mymessage:'hello brother1'
            }
        },
        template:`
            <div>
                <p>this is brother1 compoent!</p>
                <input type="text" v-model="mymessage" @input="passData(mymessage)"> 

            </div>
        `,
        methods:{
            passData(val){
                //觸發(fā)全局事件globalEvent
                bus.$emit('globalEvent',val)

            }
        }
    })
    Vue.component('brother2',{
        template:`
            <div>
                <p>this is brother2 compoent!</p>
                <p>brother1傳遞過來的數(shù)據(jù):{{brothermessage}}</p>
            </div>
        `,
        data(){
            return {
                mymessage:'hello brother2',

                brothermessage:''
            }
        },
        mounted(){
            //綁定全局事件globalEvent
            bus.$on('globalEvent',(val)=>{
                this.brothermessage=val;
            })
        }
    })
    //中央事件總線
    var bus=new Vue();

    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <brother1></brother1>
                <brother2></brother2>
            </div>
        `
    })

$attrs和$listeners

第一種方式處理父子組件之間的數(shù)據(jù)傳輸有一個問題:如果父組件A下面有子組件B授滓,組件B下面有組件C,這時如果組件A想傳遞數(shù)據(jù)給組件C怎么辦呢琳水?
如果采用第一種方法,我們必須讓組件A通過prop傳遞消息給組件B般堆,組件B在通過prop傳遞消息給組件C在孝;要是組件A和組件C之間有更多的組件,那采用這種方式就很復(fù)雜了淮摔。Vue 2.4開始提供了attrs和listeners來解決這個問題浑玛,能夠讓組件A之間傳遞消息給組件C。

Vue.component('C',{
        template:`
            <div>
                <input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)"> </div>
        `,

        methods:{
            passCData(val){
                //觸發(fā)父組件A中的事件
                this.$emit('getCData',val)
            }
        }
    })

    Vue.component('B',{
        data(){
            return {
                mymessage:this.message
            }
        },
        template:`
            <div>
                <input type="text" v-model="mymessage" @input="passData(mymessage)"> 
                <!-- C組件中能直接觸發(fā)getCData的原因在于 B組件調(diào)用C組件時 使用 v-on 綁定了$listeners 屬性 -->
                <!-- 通過v-bind 綁定$attrs屬性噩咪,C組件可以直接獲取到A組件中傳遞下來的props(除了B組件中props聲明的) -->
                <C v-bind="$attrs" v-on="$listeners"></C>
            </div>
        `,
        props:['message'],//得到父組件傳遞過來的數(shù)據(jù)
        methods:{
            passData(val){
                //觸發(fā)父組件中的事件
                this.$emit('getChildData',val)
            }
        }
    })
    Vue.component('A',{
        template:`
            <div>
                <p>this is parent compoent!</p>
                <B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"></B>
            </div>
        `,
        data(){
            return {
                message:'hello',
                messagec:'hello c' //傳遞給c組件的數(shù)據(jù)
            }
        },
        methods:{
            getChildData(val){
                console.log('這是來自B組件的數(shù)據(jù)')
            },
            //執(zhí)行C子組件觸發(fā)的事件
            getCData(val){
                console.log("這是來自C組件的數(shù)據(jù):"+val)
            }
        }
    })
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <A></A>
            </div>
        `
    })

provide和inject

父組件中通過provider來提供變量顾彰,然后在子組件中通過inject來注入變量。不論子組件有多深胃碾,只要調(diào)用了inject那么就可以注入provider中的數(shù)據(jù)涨享。而不是局限于只能從當(dāng)前父組件的prop屬性來獲取數(shù)據(jù),只要在父組件的生命周期內(nèi)仆百,子組件都可以調(diào)用厕隧。

Vue.component('child',{
        inject:['for'],//得到父組件傳遞過來的數(shù)據(jù)
        data(){
            return {
                mymessage:this.for
            }
        },
        template:`
            <div>
                <input type="tet" v-model="mymessage"> 
            </div>
    })
    Vue.component('parent',{
        template:`
            <div>
                <p>this is parent compoent!</p>
                <child></child>
            </div>
        `,
        provide:{
            for:'test'
        },
        data(){
            return {
                message:'hello'
            }
        }
    })
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })

v-model

父組件通過v-model傳遞值給子組件時,會自動傳遞一個value的prop屬性,在子組件中通過this.$emit(‘input’,val)自動修改v-model綁定的值

Vue.component('child',{
        props:{
            value:String, //v-model會自動傳遞一個字段為value的prop屬性
        },
        data(){
            return {
                mymessage:this.value
            }
        },
        methods:{
            changeValue(){
                this.$emit('input',this.mymessage);//通過如此調(diào)用可以改變父組件上v-model綁定的值
            }
        },
        template:`
            <div>
                <input type="text" v-model="mymessage" @change="changeValue"> 
            </div>
    })
    Vue.component('parent',{
        template:`
            <div>
                <p>this is parent compoent!</p>
                <p>{{message}}</p>
                <child v-model="message"></child>
            </div>
        `,
        data(){
            return {
                message:'hello'
            }
        }
    })
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })

$parent和$children

Vue.component('child',{
        props:{
            value:String, //v-model會自動傳遞一個字段為value的prop屬性
        },
        data(){
            return {
                mymessage:this.value
            }
        },
        methods:{
            changeValue(){
                this.$parent.message = this.mymessage;//通過如此調(diào)用可以改變父組件的值
            }
        },
        template:`
            <div>
                <input type="text" v-model="mymessage" @change="changeValue"> 
            </div>
    })
    Vue.component('parent',{
        template:`
            <div>
                <p>this is parent compoent!</p>
                <button @click="changeChildValue">test</button >
                <child></child>
            </div>
        `,
        methods:{
            changeChildValue(){
                this.$children[0].mymessage = 'hello';
            }
        },
        data(){
            return {
                message:'hello'
            }
        }
    })
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })

boradcast和dispatch

vue1.0中提供了這種方式吁讨,但vue2.0中沒有髓迎,但很多開源軟件都自己封裝了這種方式,比如min ui建丧、element ui和iview等排龄。
比如如下代碼,一般都作為一個mixins去使用, broadcast是向特定的父組件翎朱,觸發(fā)事件橄维,dispatch是向特定的子組件觸發(fā)事件,本質(zhì)上這種方式還是on和on和emit的封裝拴曲,但在一些基礎(chǔ)組件中卻很實用争舞。

function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    var name = child.$options.componentName;

    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat(params));
    }
  });
}
export default {
  methods: {
    dispatch(componentName, eventName, params) {
      var parent = this.$parent;
      var name = parent.$options.componentName;
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    }
  }
};

vuex

如果業(yè)務(wù)邏輯復(fù)雜,很多組件之間需要同時處理一些公共的數(shù)據(jù)澈灼,這個時候才有上面這一些方法可能不利于項目的維護竞川,vuex的做法就是將這一些公共的數(shù)據(jù)抽離出來,然后其他組件就可以對這個公共數(shù)據(jù)進行讀寫操作叁熔,這樣達到了解耦的目的流译。
詳情可參考:https://vuex.vuejs.org/zh-cn/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市者疤,隨后出現(xiàn)的幾起案子福澡,更是在濱河造成了極大的恐慌,老刑警劉巖驹马,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件革砸,死亡現(xiàn)場離奇詭異,居然都是意外死亡糯累,警方通過查閱死者的電腦和手機算利,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泳姐,“玉大人效拭,你說我怎么就攤上這事∨置耄” “怎么了缎患?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長阎肝。 經(jīng)常有香客問我挤渔,道長,這世上最難降的妖魔是什么风题? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任判导,我火速辦了婚禮嫉父,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘眼刃。我一直安慰自己绕辖,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布擂红。 她就那樣靜靜地躺著仪际,像睡著了一般。 火紅的嫁衣襯著肌膚如雪篮条。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天吩抓,我揣著相機與錄音涉茧,去河邊找鬼。 笑死疹娶,一個胖子當(dāng)著我的面吹牛伴栓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雨饺,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼钳垮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了额港?” 一聲冷哼從身側(cè)響起饺窿,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎移斩,沒想到半個月后肚医,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡向瓷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年肠套,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猖任。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡你稚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出朱躺,到底是詐尸還是另有隱情刁赖,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布长搀,位于F島的核電站乾闰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盈滴。R本人自食惡果不足惜涯肩,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一轿钠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧病苗,春花似錦疗垛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至咬展,卻和暖如春泽裳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背破婆。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工涮总, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祷舀。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓瀑梗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親裳扯。 傳聞我的和親對象是個殘疾皇子抛丽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

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

  • 1、props / $emit (這是最常用的一種父子組件之間傳遞數(shù)據(jù)的方式) 父組件通過綁定屬性來向子組件傳遞數(shù)...
    keke柯柯柯閱讀 834評論 0 0
  • 對于vue來說饰豺,組件之間的消息傳遞是非常重要的亿鲜,下面是我對組件之間消息傳遞的各種方式的總結(jié),總共有8種方式冤吨。 pr...
    紫痕藍羽閱讀 409評論 0 0
  • Vue組件之間通信的七種方式 使用Vue也有很長一段時間,但是一直以來都沒對其組件之間的通信做一個總結(jié),這次就借此...
    豆豆_4edc閱讀 612評論 0 2
  • vue是數(shù)據(jù)驅(qū)動視圖更新的框架, 所以對于vue來說組件間的數(shù)據(jù)通信非常重要狡门,那么組件之間如何進行數(shù)據(jù)通信的呢?首...
    云翼飛閱讀 545評論 0 0
  • 對于vue來說锅很,組件之間的消息傳遞是非常重要的其馏,下面是我對組件之間消息傳遞的各種方式的總結(jié),總共有8種方式爆安。 1....
    edc余悸閱讀 350評論 0 3