上篇學習了如何把父組件的數據傳遞給子組件,盡管子組件內部不能改變prop的值,但子組件能把自己的數據傳遞給父組件。
我們通過自定義事件來實現。
#事件綁定
$on(eventName) 監聽事件
$emit(eventName) 觸發事件
父組件可以在使用子組件的地方直接用v-on來監聽子組件觸發的事件
[注意]不能用$on偵聽子組件拋出的事件,直接在模板里用v-on綁定
HTML
<div id="example"> <parent></parent> </div>
Js
var childNode = { template: `<button @click="incrementCounter">{{ counter }}</button>`, data() { return { counter: 0 } }, methods: { incrementCounter() { this.counter++; this.$emit('increment'); // 子組件內用$emit觸發事件 } }, }; var parentNode = { // 父組件內通過v-on(簡寫@)監聽事件 template: ` <div class="parent"> <p>{{total}}</p> <child @increment="incrementTotal"></child> <child @increment="incrementTotal"></child> </div> `, components: { 'child': childNode //聲明子組件 }, data() { return { 'total': 0 } }, methods: { incrementTotal() { this.total++; } } }; // 創建根實例 new Vue({ el: '#example', components: { 'parent': parentNode //聲明父組件 } })
上面的代碼中,子組件button一旦發生click事件,就會執行incrementCounter方法,而incrementCounter()會通過$emit觸發increment事件,而在父組件內,通過v-on(簡寫@)監聽increment事件,一旦increment被觸發,則執行incrementTotal方法。
最終實現的效果如圖
左邊點擊一次右邊點擊兩次:
#數據傳遞
子組件通過$emit觸發事件,$emit方法的第一個參數為要觸發的事件,第二個參數為要傳遞的數據。
var childNode = { template: ` <div class="child"> <div> <span>子組件數據</span> <input v-model="childMsg" @input="data"> </div> <p>{{childMsg}}</p> </div> `, data() { return { childMsg: '' } }, methods: { data() { this.$emit('pass-data', this.childMsg) // pass-data為被觸發的事件,this.childMsg為要傳遞給父組件的數據 } } } var parentNode = { // v-on監聽pass-data是否被觸發,如果觸發了,就執行getData方法 template: ` <div class="parent"> <div> <span>父組件數據</span> <input v-model="msg"> </div> <p>{{msg}}</p> <child @pass-data="getData"></child> </div> `, components: { 'child': childNode }, data() { return { 'msg': 'match' } }, methods: { getData(value) { // getData方法接收的參數value的值就是從子組件接收的數據this.childMsg this.msg = value; } } }; // 創建根實例 new Vue({ el: '#example', components: { 'parent': parentNode } })
最終效果如下
修改子組件中input值,父組件則接收到相同的值並顯示出來