vue組件之間通訊的8種方式

對於vue來講,組件之間的消息傳遞是很是重要的,下面是我對組件之間消息傳遞的經常使用方式的總結。vue

  • props和$emit(經常使用)
  • $attrs和$listeners
  • 中央事件總線(非父子組件間通訊)
  • v-model
  • provide和inject
  • $parent和$children
  • vuex

1.props和$emitvuex

   父組件向子組件傳遞數據是經過prop傳遞的,子組件傳遞數據給父組件是經過$emit觸發事件來作到的.app

 1 Vue.component('child',{
 2     data(){
 3       return {
 4         mymessage:this.message
 5       }
 6     },
 7     template:`
 8       <div>
 9         <input type="text" v-model="mymessage" @input="passData(mymessage)"> </div>
10     `,
11     props:['message'],//設置props屬性值,獲得父組件傳遞過來的數據
12     methods:{
13       passData(val){
14         //觸發父組件中的事件,向父組件傳值
15         this.$emit('getChildData',val)
16       }
17     }
18   })
19   Vue.component('parent',{
20     template:`
21       <div>
22         <p>this is parent compoent!</p>
23         <child :message="message" v-on:getChildData="getChildData"></child>
24       </div>
25     `,
26     data(){
27       return {
28         message:'hello'
29       }
30     },
31     methods:{
32       //執行子組件觸發的事件
33       getChildData(val){
34         console.log(val)
35       }
36     }
37   })

 

 在上面的例子中,有父組件parent和子組件child。ide

  1).父組件傳遞了message數據給子組件,而且經過v-on綁定了一個getChildData事件來監聽子組件的觸發事件;this

  2).子組件經過props獲得相關的message數據,最後經過this.$emit觸發了getChildData事件spa

2.$attrs和$listeners.net

  第一種方式處理父子組件之間的數據傳輸有一個問題:若是父組件A下面有子組件B,組件B下面有組件C,這時若是組件A想傳遞數據給組件C怎麼辦呢? 若是採用第一種方法,咱們必須讓組件A經過prop傳遞消息給組件B,組件B在經過prop傳遞消息給組件C;要是組件A和組件C之間有更多的組件,那採用這種方式就很複雜了。Vue 2.4開始提供了$attrs和$listeners來解決這個問題,可以讓組件A之間傳遞消息給組件C。code

 1 Vue.component('C',{
 2     template:`
 3       <div>
 4         <input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)"> </div>
 5     `,
 6     methods:{
 7       passCData(val){
 8         //觸發父組件A中的事件
 9         this.$emit('getCData',val)
10       }
11     }
12   })
13   Vue.component('B',{
14     data(){
15       return {
16         mymessage:this.message
17       }
18     },
19     template:`
20       <div>
21         <input type="text" v-model="mymessage" @input="passData(mymessage)">
22         <!-- C組件中能直接觸發getCData的緣由在於 B組件調用C組件時 使用 v-on 綁定了$listeners 屬性 -->
23         <!-- 經過v-bind 綁定$attrs屬性,C組件能夠直接獲取到A組件中傳遞下來的props(除了B組件中props聲明的) -->
24         <C v-bind="$attrs" v-on="$listeners"></C>
25       </div>
26     `,
27     props:['message'],//獲得父組件傳遞過來的數據
28     methods:{
29       passData(val){
30         //觸發父組件中的事件
31         this.$emit('getChildData',val)
32       }
33     }
34   })
35   Vue.component('A',{
36     template:`
37       <div>
38         <p>this is parent compoent!</p>
39         <B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"></B>
40       </div>
41     `,
42     data(){
43       return {
44         message:'hello',
45         messagec:'hello c' //傳遞給c組件的數據
46       }
47     },
48     methods:{
49       getChildData(val){
50         console.log('這是來自B組件的數據')
51       },
52       //執行C子組件觸發的事件
53       getCData(val){
54         console.log("這是來自C組件的數據:"+val)
55       }
56     }
57   })

 3. 中央事件總線component

上面兩種方式處理的都是父子組件之間的數據傳遞,而若是兩個組件不是父子關係呢?這種狀況下可使用中央事件總線的方式。新建一個Vue事件bus對象,而後經過bus.$emit觸發事件,bus.$on監聽觸發的事件。對象

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){
        //觸發全局事件globalEvent
        bus.$emit('globalEvent',val)
      }
    }
  })
  Vue.component('brother2',{
    template:`
      <div>
        <p>this is brother2 compoent!</p>
        <p>brother1傳遞過來的數據:{{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>
    `
  })

4. provide和inject

  在 Vue.js 的 2.2.0+ 版本中添加加了 provide 和 inject 選項。他們成對出現,用於父級組件向下傳遞數據。

父組件中經過provider來提供變量,而後在子組件中經過inject來注入變量。不論子組件有多深,只要調用了inject那麼就能夠注入provider中的數據。而不是侷限於只能從當前父組件的prop屬性來獲取數據,只要在父組件的生命週期內,子組件均可以調用。

 1 Vue.component('child',{
 2     inject:['for'],//獲得父組件傳遞過來的數據
 3     data(){
 4       return {
 5         mymessage:this.for
 6       }
 7     },
 8     template:`
 9       <div>
10         <input type="tet" v-model="mymessage">
11       </div>
12   })
13   Vue.component('parent',{
14     template:`
15       <div>
16         <p>this is parent compoent!</p>
17         <child></child>
18       </div>
19     `,
20     provide:{
21       for:'test'
22     },
23     data(){
24       return {
25         message:'hello'
26       }
27     }
28   })

 

5. 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);//經過如此調用能夠改變父組件上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>
    `
  })

 

 6. $parent和$children

      在組件內部能夠直接經過子組件$parent對父組件進行操做,父組件經過$children對子組件進行操做.

Vue.component('child',{
    props:{
      value:String, //v-model會自動傳遞一個字段爲value的prop屬性
    },
    data(){
      return {
        mymessage:this.value
      }
    },
    methods:{
      changeValue(){
        this.$parent.message = this.mymessage;//經過如此調用能夠改變父組件的值
      }
    },
    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>
    `
  })

7. vuex處理組件之間的數據交互

若是業務邏輯複雜,不少組件之間須要同時處理一些公共的數據,這個時候纔有上面這一些方法可能不利於項目的維護,vuex的作法就是將這一些公共的數據抽離出來,而後其餘組件就能夠對這個公共數據進行讀寫操做,這樣達到了解耦的目的。

 參考連接:https://my.oschina.net/u/3982182/blog/3019264

相關文章
相關標籤/搜索