父組件及子組件由於屬於不同的實體,不能直接在一個組件上使用另一個組件的方法或是修改資料,而是必須要使用 props 屬性及 $emit 方法來進行溝通。

子組件只要在 props 屬性加上需要由父組件傳入的參數定義,父組件就可以在配置子組件的時候給予子組件所需的參數屬性,而如果子組件因為變動需要通知父組件,就可以使用 $emit 通知父組件,而父組件只要設定相關事件的處理函數就可以接收到子組件的資料。
在子組件使用 props 屬性註冊客製屬性,由父組件設定在子組件的屬性會變為實體中的屬性,如此一來就可以在子組件中使用由父組件傳來的資料。
跟前一篇一樣使用計算按鈕為例:
Vue.component('button-counter', {
template: `
<button @click="count+=1">
{{buttonName}} {{count}} times
</button>
`,
props: ['buttonName'],
data: function() {
return {
count: 0,
};
},
});
在 props 中設定 buttonName ,表示 buttonName 是一個客製屬性,會由父組件在設定模板時給予它的值。
接著設定父組件:
<div id="app">
<button-counter button-name="Click me"></button-counter>
</div>
var vm = new Vue({
el: '#app',
});
在父組件上以 kebab Case 設定客製屬性 button-name ,將它的值設為 Click me 。
接著我們可以看到結果如下圖:

也可以使用 v-bind 綁定資料屬性:
var vm = new Vue({
el: '#app',
data: {
buttonName: ''
}
});
<div>
<input v-model='buttonName'>
<button-counter :button-name="buttonName"></button-counter>
</div>

v-for 帶入屬性大部分的時候我們都會是有一包資料,這包資料中的每一筆都有多個屬性,因此想要在頁面上顯示這樣的資料時,可以使用組件跟 v-for 的組合來完成。
例如,我們需要有多個計數器,每個計數器會有一個標題及一對加減按紐:
Vue.component('counter', {
template: `
<div>
<h3>{{title}}</h3>
<button @click="count+=1">{{plusBtnName}}</button>
<button @click="count-=1">{{minusBtnName}}</button>
Count: {{count}}
<div>
`,
props: ['title', 'plusBtnName', 'minusBtnName'],
data: function() {
return {
count: 0,
};
},
});
註冊 counter 組件,這個組件有三個 props 屬性: title 、 plusBtnName 及 minusBtnName 。
接著在 new Vue 實體上設定 v-for 要巡覽的資料:
var vm = new Vue({
el: '#app',
data: {
counters: [{
title: 'Counter',
plusBtnName: '+',
minusBtnName: '-'
}, {
title: 'Counter',
plusBtnName: 'Plus',
minusBtnName: 'Minus'
}, {
title: '計數器',
plusBtnName: '加',
minusBtnName: '減'
}]
}
});
接著在模板上配置 v-for 屬性渲染頁面:
<div>
<counter v-for="counter in counters"
:title="counter.title"
:plus-btn-name="counter.plusBtnName"
:minus-btn-name="counter.minusBtnName"></counter>
</div>
這樣就可以完成設置了,結果如下圖:

上例我們設定了三個屬性要傳入子組件中,可是它們都屬於 counter 資料物件,因此我們可以直接傳入 coounter 物件就好。
修改 counter 組件設置如下:
Vue.component('counter-simple', {
template: `
<div>
<h3>{{counter.title}}</h3>
<button @click="count+=1">{{counter.plusBtnName}}</button>
<button @click="count-=1">{{counter.minusBtnName}}</button>
Count: {{count}}
<div>
`,
props: ['counter'], // 簡化為 counter 屬性
data: function() {
return {
count: 0,
};
},
});
<div>
<counter-simple v-for="counter in counters"
:counter="counter"></counter-simple>
</div>
父組件只需要傳入 counter 屬性。
$emit 反應子組件中的變化當事件或是監聽器觸發時,子組件可以用 $emit 方法將變化反應給父組件知道。
還是以 button-counter 為例:
Vue.component('button-counter', {
template: `
<button @click="clickPlus">
{{buttonName}} {{count}} times
</button>
`,
props: ['buttonName'],
data: function() {
return {
count: 0,
};
},
methods: {
clickPlus: function() {
this.count += 1;
this.$emit('click-plus');
}
}
});
click 事件改為叫用 clickPlus 方法,這個方法做了兩件事:
count 加一。click-plus 事件。接著只要在父組件中的 button-counter 中設定 click-plus 事件的綁定就可以監看此事件:
<div>
{{count}}
<button-counter button-name="Click me" @click-plus="count += 1"></button-counter>
</div>
如此一來我們就可以更新父組件內的 count 了。
剛剛的例子有一個問題: 父組件的 count 並沒有跟 button-counter 中的 count 同步,為了解決這個問題,我們可以將 button-counter 內的 count 傳給父組件。
methods: {
clickPlus: function() {
this.count += 1;
this.$emit('click-plus', this.count);
}
}
$emit 第二個參數傳入想要傳給父組件的資料,這裡是 count 。
接著在父組件中使用 $event 當作傳回的資料做處理:
<button-counter button-name="Click me" @click-plus="count=$event"></button-counter>
如果使用方法名稱的方式設定客製事件,第一個參數就是傳入的資料:
<button-counter button-name="Click me" @click-plus="clickPlus"></button-counter>
methods: {
clickPlus(count) {
this.count = count
}
}
如此一來就解決了同步的問題。
v-model在來複習 v-model ,它是雙向綁定的屬性,如下面的範例設定:
<input v-model="inputSomething">
v-model 其實是 value 及 @input 的語法糖,也就是提供開發者叫簡潔的定義方式,所以他原本是:
<input :value="inputSomething" @input="inputSomething=$event.target.value">
value 屬性的資料綁定到 DOM 元素上的 value 。input 事件觸發時將 value 的資料改為新的值。因此要在客製的 input 組件上使用 v-model 的話,需要做下面三點設定:
value 客製屬性。value 客製屬性綁定到 DOM 元素上的 value 屬性。input 事件的時候,使用 $emit 觸發上層的 input 事件,並帶入改變後的值。Vue.component('custom-input', {
template: `
<div>
<h3>{{title}}</h3>
<input :value="value"
@input="$emit('input', $event.target.value)">
<div>
`,
props: ['title', 'value'],
});
接著在父組件上的 custom-input 設定 v-model 屬性:
<input v-model="inputSomething">
記住 v-model 是 :value 及 @input 的語法糖, inputSomething 會綁定 value 的值,並且會隨 input 事件所更新。
本文承接前一篇介紹的組件,更進一步的說明組件間的傳遞方式,上對下的是使用 props 屬性,下對上使用 $emit 方法,而最後透過已學習到的組件傳遞方式講述 v-model 在組件上如何使用。
到這章為止,基本的 Vue.js 使用方式已經有了較全面的了解,可以開始著手些一個小專案了,接下來我們將深入講解組件各式各樣的設定。
傳入的組件參數跟父接變數 相同.會出錯
Vue.component('button-counter', {
template: `
<button @click="count+=1">
{{buttonName}} {{count}} times
</button>
`,
props: ['buttonName'],
data: function() {
return {
count: 0,
};
},
});
<div>
<input v-model='buttonName'>
<button-counter :button-name="buttonName"></button-counter>
</div>
var vm = new Vue({
el: '#app',
data: {
buttonName0: 'AAAA',
counters: [{
title: 'Counter',
plusBtnName: '+',
minusBtnName: '-'
}, {
title: 'Counter',
plusBtnName: 'Plus',
minusBtnName: 'Minus'
}, {
title: '計數器',
plusBtnName: '加',
minusBtnName: '減'
}],
count: 0,
inputSomething: ''
},
methods: {
clickPlus(count) {
this.count = count
}
}
});
應該為
<input v-model='buttonName0'>
<button-counter :button-name="buttonName0"></button-counter>
new Vue 那邊也要改成 buttonName0
組件的命名 也參考