vue---組件間通訊

vue中比較重要的就是組件了。而組件隨處可複用的特性,使得組件通訊很是重要。那麼組件之間通信方式有哪些呢?html

第一種:父子組件通信:vue

若是是 html頁面 中全局註冊的組件 和 實例中局部註冊的組件ajax

HTML:數組

<div id="box"></div>

JS:異步

Vue.component('child',{
    name:'child',
    props:{
        msg:{
            type:String,
            require:true
        }
    },
    template:`
        <div id='getChild'>
            <h3>我是child組件</h3>
            <p>{{msg}}</p>
            <button @click='getParentVal'>點擊獲取父組件內容</button>
            <button @click='sendVal'>向父組件傳遞內容</button>
        </div>
    `,
    data:function(){
        return {
            childVal:'我是子組件中的數據'
        }
    },
    methods:{
        //這裏是獲取父組件中的屬性或方法
        getParentVal:function(){
            console.log(this.$parent.age)
        },
        //這個是向父組件傳遞指定的內容
        sendVal:function(){
            this.$emit('sendChild',{
                mssg:'我是子組件$emit傳過來的內容'
            })
        }
    }
})
Vue.component('myParent',{
    name:'parent',
    template:`
        <div>
            <button @click='getVal'>點我獲取子組件內容</button>
            <child :msg='parentVal' ref='getChild' @sendChild='getSendChild'></child>    
        </div>
    `,
    data:function(){
        return {
            parentVal:'我是parent組件傳過來的值',
            age:666
        }
    },
    methods:{
        //這個是獲取子組件的屬性或方法
        getVal:function(){
            console.log(this.$refs.getChild.childVal)
        },
        //這個是獲取子組件經過emit傳遞過來的內容
        getSendChild:function(res){
            console.log(res)
        }
    }
})

new Vue({
    el:'#box',
  //這裏局部註冊父組件
  template:`
    <my-parent></my-parent>
  `
})

注意事項:ide

1) 組件須要先註冊才能使用,註冊又分 局部註冊 和 全局註冊。局部註冊須要在實例裏面的template聲明組件的內容,全局註冊即如上例同樣。函數

2) 組件名支持駝峯小寫大寫,橫線(xxx-xxx)的寫法。可是在使用組件的時候,若是是駝峯的寫法,則需要寫成橫線的形式。如上面 組件名是myParent ,那麼使用的時候 就必須是 <my-parent></my-parent> 。ui

3) 父組件能夠獲取子組件的數據和方法,經過在引用子組件的時候定義 ref='自定義名稱'  ,而後在子組件的template中最外層節點定義一個id值,而後父組件中使用  this.$refs.自定名稱.子組件數據  。就如同上例點擊獲取子組件數據同樣。或者不加ref,直接使用 this.$children[第幾個子組件].子組件數據this

4) 子組件能夠獲取父組件的數據和方法,在子組件中使用 this.$parent.子組件數據。es5

5) 子組件經過 $emit('自定義名稱',數據) 來達到向父組件傳遞指定的數據,相似 jQuery 的 trigger 。

6) 父組件經過 實例.$on('對應emit定義的名稱',function(res){}) 或者  在引用子組件的時候   <child @對應emit定義的名稱='本身定義的函數名'></child> ,而後在methods中指定  本身定義的函數名  獲取到的  res 就是子組件傳過來的值。

7) template 裏面的內容 能夠用  ` `  就是鍵盤上 esc 下面的那個波浪鍵 在英文狀態下打出來的內容  ,這樣就不用向es5同樣用 + 加號和 ' ' 引號來合併成字符串了。

8) props 中命名方式 不支持 xxx-xxx 這種橫線的格式支持駝峯,小寫。若是props中是駝峯的命名方式,那引用組件的時候就要寫成對應的橫線方式,例如props:[getPhone]   那麼<child get-phone='xxx'></child> ,若是綁定的是動態值也是同樣的寫法<child :get-phone='xxx'></child>  。緣由:因爲html不區分大小寫的特性,因此無法對應組件中的駝峯名稱。

9) 爲何組件中的data必須是函數,而後返回對象?由於組件是用於複用的,彼此之間的數據必定要是惟一的。因此若是data就是一個對象,那麼因爲對象是引用類型,不一樣地方引用同一個對象,並非引用的值,而是引用的對象的地址,因此某一處修改以後,其它的也會跟着變化,這樣就不能達到數據惟一的目的。而使用函數再返回一個對象,每一個對象的地址都是不一樣的,就能保證每次都是一個新的對象。

10)props驗證方式的寫法能夠查看官網,裏面的prop驗證

11) template 裏面的內容必須只有一個根元素。

 

若是是 .vue 這種單文件模塊 的組件

這種方式和 html 頁面 中註冊組件有稍許的不同。

//child 組件
<template>
    <div>
        xxxx
    </div>
</template>
<script>
    export default {
        props:[],
        data:function(){}
    }
</script>
<style>

</style>   

  

//parent 組件
<template>
    <div>
        <childComponent></childComponent>
        //若是註冊的時候不重命名的話就可使用<child></child>
    </div>
</template>
<script>
    import child from 'xxx'
    export default {
        data:function(){},   
        components:{
            'childComponent':child  //若是不重名的話能夠直接是{child}
        },
        data:function(){}
    }
</script>
<style>

</style> 

 說明:

1) 每一個 .vue單文件組件模塊,都須要在 template 中聲明組件的內容,而且也只有一個根元素

2) 在script 裏面 須要 export default 組件註冊的必須內容,例如props,data,mthods等。

3) 在須要引入組件的頁面  import  自定義組件名稱  from  'xxx' 。組件的名稱自定義,支持大寫,小寫,駝峯,橫線(xxx-xxx)

4) import 組件以後,還須要在components中註冊組件。註冊的時候也能夠重命名組件名稱。

5) 除了上面的區別,其它的就沒什麼區別了,組件的通信也和上面 html頁面中組件通信同樣的處理方式。

 

第二種:非父子組件之間的通信。

在 html 頁面中,註冊方式與父子組件無差異,也是全局註冊和局部註冊。

HTML:

<div id="box"></div>

JS:

//全局註冊mine組件
Vue.component('mine',{
    template:`
        <div>
            我是mine組件
            <button @click='sendToBrother'>點擊向brother組件發送內容</button>
        </div>
    `,
    data:function(){
        return {
            name:'mine',
            sex:'male'
        }
    },
    mounted:function(){
        //接收mine組件傳過來的內容
        transfer.$on('brotherVal',function(res){
            console.log(res)
        })
    },
    methods:{
        //向brother組件傳遞內容
        sendToBrother:function(){
            transfer.$emit('mineVal',this.name)
        }
    }
})
//全局註冊brother組件   
Vue.component('brother',{
    template:`
        <div>
            我是brother組件
            <button @click='sendToMine'>點擊向mine組件發送內容</button>
        </div>
    `,
    data:function(){
        return {
            name:'brother',
            age:666
        }
    },
    mounted:function(){
        //接收mine組件傳過來的內容
        transfer.$on('mineVal',function(res){
            console.log(res)
        })
    },
    methods:{
        //向mine組件發送內容
        sendToMine:function(){
            transfer.$emit('brotherVal',this.name)
        }
    }
})

//這是最重要的一步,定一個空的實例對象。
var transfer=new Vue();

new Vue({
    el:'#box',
    data:{},
    //局部註冊兩個組件
    template:`
        <div>
          <mine></mine>
          <brother></brother>
        </div>
     `
})

說明:

1) 主要的就是經過一個 中間實例對象來實現 非父子組件之間的通信

2) 仍是經過 $emit() 來發送內容 , $on() 來接收傳遞過來的內容 ,只是使用這兩個方法的對象並非 this 而是 一個空的實例對象。要注意 $on 和 $emit 中的事件名要對應

3) 不必定是mounted的時候纔去接收傳過來的內容,created的時候也是能夠的。應該是隻要生命週期裏,數據初始化完成以後都行。

4) 具體是什麼原理,我不清楚。也感受不必去搞懂

 

若是是 .vue 這種單文件模塊 的組件

這種方式和 html 頁面 中註冊組件有稍許的不同。並且通信的方式也有一點差距。

第一步:須要中間實例對象,因而新建一個  transfer.js

import Vue from 'vue'
export default new Vue();

第二步:須要傳值的頁面,引入這個js

//mine 組件
<template>
    <div>
        <button @click='sendToBrother'>點我向brother組件發送內容</button>
    </div>
</template>
<script>
    import transfer from 'transfer.js的路徑'
    export default {
        data:function(){
           return {}  
        },
        methods:{
            sendToBrother:function(){
                transfer.$emit('sendVal','這是mine組件傳過來的值')
            }    
        }
    }
</script>
<style>

</style>          
//brother 組件
<template>
    <div>
        xxx
    </div>
</template>
<script>
    import transfer from 'transfer.js的路徑'
    export default {
        data:function(){
           return {}  
        },
        mounted:function(){
            transfer.$on('sendVal',function(res){
                console.log(res)
            })
        }
    }
</script>
<style>

</style>          

第三步:在引用這兩個組件的地方,註冊這兩個組件。

//引入組件的頁面
<template>
    <div>
        <mine></mine>
        <brother></brother>
    </div>
</template>
<script>
    import mine from 'mine組件的路徑';
    import brother from 'brother組件的路徑'
    export default {
        data:function(){
           return {}  
        },
        components:{ mine ,brother },
    }
</script>
<style>

</style>        

說明:

1) 實現的方式仍是差很少的 , 都是 $on 接收內容   $emit 發送內容。

2) 只是中間實例對象須要添加到一個 js 中。而後兩個組件頁面都須要引入

3) 這種經過中間實例對象的方式,也能夠用於  父子、祖孫 等關係的組件通信。

 

上面的通信方式是最多見的。可是在組件通信這塊,vue 2.4 版本又增長了 inheritAttrs、attrs和listeners 。這三個的用法,後面再找個機會補上。

 


 

若是遇到 父級組件須要傳給 子級組件的props值 是經過  ajax  異步請求  傳入的  。那麼,在子組件的生命週期中獲取該props內容是獲取不了的。就算是在mounted 中也是獲取不了的。

這個時候的解決辦法是:

<childComponent  :sendVal='getval'  v-if='getval'></childComponent>

 

必定要加一個  v-if ,這樣才能在 子組件的 mounted 中獲取到該值。這個地方是把我坑慘的。。。網上有推薦說若是是數組,可使用  v-if = 'getval.length' 。這徹底不必,並且有可能還會報錯,由於getval的值有可能還沒返回來,再去取length確定會報錯。 若是是布爾值的話,更要注意點。

相關文章
相關標籤/搜索