組件之間通信可以用下圖表示: 組件關係可分為父子組件通信、兄弟組件通信、跨級組件通信。 一、自定義事件 當子組件需要向父組件傳遞數據時,就要用到自定義事件。 子組件用$emit ()來觸發事件,父組件用$on()來監昕子組件的事件。 父組件可以直接在子組件的自定義標簽上使用v-on 來監昕子組件觸發 ...
組件之間通信可以用下圖表示:
組件關係可分為父子組件通信、兄弟組件通信、跨級組件通信。
一、自定義事件
當子組件需要向父組件傳遞數據時,就要用到自定義事件。
子組件用$emit ()來觸發事件,父組件用$on()來監昕子組件的事件。
父組件可以直接在子組件的自定義標簽上使用v-on 來監昕子組件觸發的自定義事件,如:
<div id="app9"> <p>總數:{{total}}</p> <my-component9 @add="getTotal" @cut="getTotal"></my-component9> </div>
Vue.component('my-component9',{ template: '<div>' + ' <button @click="increase">+1</button>' + ' <button @click="reduce">-1</button>' + '</div>', data: function(){ return { count: 0 } }, methods:{ increase: function(){ this.count++; this.$emit('add',this.count) //廣播的事件名和數據 }, reduce: function(){ this.count--; this.$emit('cut',this.count) //廣播的事件名和數據 } } }); var app9 = new Vue({ el: '#app9', data:{ total: 0 }, methods:{ getTotal: function(count){ this.total = count; } } });
二、使用v-model
Vue2 .x 可以在自定義組件上使用v-model 指令,直接看一個事例:
<div id="app10"> <p>總數:{{total}}</p> <my-component10 v-model="total"></my-component10> //這個地方v-model實際是一個語法糖,可以直接理解為接收到廣播input裡面的數據(this.total=count)。 </div>
Vue.component('my-component10',{ template: '<div>' + '<button @click="increase">+1</button>' + '<button @click="reduce">-1</button>' + '</div>', data: function(){ return { count: 0 } }, methods:{ increase: function(){ this.count++; this.$emit('input',this.count) //註意這個地方,廣播的事件名稱為特殊的input }, reduce: function(){ this.count--; this.$emit('input',this.count) //註意這個地方,廣播的事件名稱為特殊的input } } }); var app10 = new Vue({ el: '#app10', data:{ total: 0 } });
v-model 還可以用來創建自定義的表單輸入組件, 進行數據雙向綁定,例如:
<div id="app11"> <p>總數:{{total}}</p> <my-component11 v-model="total"></my-component11> <button @click="reduce">-1</button> </div>
Vue.component('my-component11', { props: ['value'], //使用v-model的表單組件時,父組件通過value來進行傳值 template: '<input :value="value" @input="updateValue">', methods: { updateValue: function(event){ this.$emit('input', event.target.value); } } }); var app11 = new Vue({ el: '#app11', data:{ total: 0 }, methods:{ reduce: function(){ this.total-- } } });
父組件的total發生變化時,會通過傳遞value值,影響子組件input中的value值,而子組件改變自己input中的value值,又會廣播給父組件,影響父組件中的total值。
實現這樣一個具有雙向綁定的v -model 組件要滿足下麵兩個要求:
•接收一個value 屬性。
• 在有新的value 時觸發input 事件。
三、非父子組件通信
在Vue . 2.x 中, 推薦使用一個空的Vue 實例作為中央事件匯流排( bu s ),也就是一個中介。
直接看一個事例:
<div id="app12"> <p>{{message}}</p> <my-component12></my-component12> </div>
var bus = new Vue(); Vue.component('my-component12',{ template: '<button @click="updateMessage">傳遞事件信息</button>', methods: { updateMessage: function(){ bus.$emit('updateMessage','更新我的組件信息'); //利用中介bus傳播事件 } } }); var app12 = new Vue({ el: '#app12', data:{ message: '' }, mounted: function(){ var _this = this; //這一步賦值必須有 bus.$on('updateMessage',function(data){ //利用中介bus接收事件 _this.message = data; }) } });
在app 初始化時,也就是在生命周期mounted 鉤子函數里監聽了來自bus 的事件updateMessage(mounted掛載這一步相當於在兩個組件直間提前安排了一個中介,當兩個組件通信時,就可以通過該中介相互傳遞消息了) ,
而在組件my-component12中,點擊按鈕會通過bus 把事件updateMessage發出去,此時app 就會接收到來自bus 的事件,進而在回調里完成自己的業務邏輯。
這種方法巧妙而輕量地實現了任何組件間的通信,包括父子、兄弟、跨級,而且Vue 1.x 和Vue 2.x 都適用。
四、父鏈與子組件索引
除了中央事件匯流排bus 外,還有兩種方法可以實現組件間通信:父鏈和子組件索引。
在子組件中,使用this.$parent 可以直接訪問該組件的父實例或組件,父組件也可以通過this.$children 訪問它所有的子組件,而且可以遞歸向上或向下無線訪問, 直到根實例或最內層的組件。
4.1父鏈
<div id="app13"> <p>{{message}}</p> <my-component13></my-component13> </div>
Vue.component('my-component13',{ template: '<button @click="updateMessage">通過父鏈直接修改數據</button>', methods: { updateMessage: function(){ this.$parent.message = '來自組件my-component13的內容' //通過this.$parent直接修改父組件的內容 } } }); var app13 = new Vue({ el: '#app13', data:{ message: '' } });
儘管V ue 允許這樣操作,但在業務中, 子組件應該儘可能地避免依賴父組件的數據,更不應該去主動修改它的數據,因為這樣使得父子組件緊藕合,理想情況下,只有組件自己能修改它的狀態。
4.2 子組件索引
當子組件較多時, 通過this.$children 來一一遍歷出我們需要的一個組件實例是比較困難的,尤其是組件動態渲染時,它們的序列是不固定的。Vue 提供了子組件索引的方法,用特殊的屬性ref來為子組件指定一個索引名稱。
<div id="app14"> <p>{{message}}</p> <my-component14 ref="com14"></my-component14> <button @click="handleRef">通過ref獲取子組件實例</button> </div>
Vue.component('my-component14',{ template: '<div>子組件</div>', data: function(){ return { message: '子組件內容' } } }); var app14 = new Vue({ el: '#app14', data:{ message: '' }, methods: { handleRef: function(){ this.message = this.$refs.com14.message; //通過$refs獲取子組件實例 } } });
在父組件模板中,子組件標簽上使用ref 指定一個名稱,井在父組件內通過this.$refs 來訪問指定名稱的子組件。
$refs 只在組件渲染完成後才填充,並且它是非響應式的. 它僅僅作為一個直接訪問子組件的應急方案,應當儘量避免在模板或計算屬性中使用$refs。