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確定會報錯。 若是是布爾值的話,更要注意點。