Vue.js 組件
組件(Component)是 Vue.js 最強大的功能之一。
組件可以擴展 HTML 元素,封裝可重用的代碼。
組件系統讓我們可以用獨立可複用的小組件來構建大型應用,幾乎任意類型的應用的介面都可以抽象為一個組件樹:

註冊一個全局組件語法格式如下:
Vue.component(tagName, options)
tagName 為組件名,options 為配置選項。註冊後,我們可以使用以下方式來調用組件:
<tagName></tagName>
全局組件
所有實例都能用全局組件。
全局組件實例
註冊一個簡單的全局組件 zaixian,並使用它:
<div id="app">
<zaixian></zaixian>
</div>
<script>
// 註冊
Vue.component('zaixian', {
template: '<h1>自定義組件!</h1>'
})
// 創建根實例
new Vue({
el: '#app'
})
</script>
局部組件
我們也可以在實例選項中註冊局部組件,這樣組件只能在這個實例中使用:
局部組件實例
註冊一個簡單的局部組件 zaixian,並使用它:
<div id="app">
<zaixian></zaixian>
</div>
<script>
var Child = {
template: '<h1>自定義組件!</h1>'
}
// 創建根實例
new Vue({
el: '#app',
components: {
// <zaixian> 將只在父範本可用
'zaixian': Child
}
})
</script>
Prop
prop 是子組件用來接受父組件傳遞過來的數據的一個自定義屬性。
父組件的數據需要通過 props 把數據傳給子組件,子組件需要顯式地用 props 選項聲明 "prop":
Prop 實例
<div id="app">
<child message="hello!"></child>
</div>
<script>
// 註冊
Vue.component('child', {
// 聲明 props
props: ['message'],
// 同樣也可以在 vm 實例中像 "this.message" 這樣使用
template: '<span>{{ message }}</span>'
})
// 創建根實例
new Vue({
el: '#app'
})
</script>
動態 Prop
類似於用 v-bind 綁定 HTML 特性到一個運算式,也可以用 v-bind 動態綁定 props 的值到父組件的數據中。每當父組件的數據變化時,該變化也會傳導給子組件:
Prop 實例
<div id="app">
<div>
<input v-model="parentMsg">
<br>
<child v-bind:message="parentMsg"></child>
</div>
</div>
<script>
// 註冊
Vue.component('child', {
// 聲明 props
props: ['message'],
// 同樣也可以在 vm 實例中像 "this.message" 這樣使用
template: '<span>{{ message }}</span>'
})
// 創建根實例
new Vue({
el: '#app',
data: {
parentMsg: '父組件內容'
}
})
</script>
以下實例中使用 v-bind 指令將 todo 傳到每一個重複的組件中:
Prop 實例
<div id="app">
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
new Vue({
el: '#app',
data: {
sites: [
{ text: 'zaixian' },
{ text: 'Google' },
{ text: 'Taobao' }
]
}
})
</script>
注意: prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是不會反過來。
Prop 驗證
組件可以為 props 指定驗證要求。
為了定制 prop 的驗證方式,你可以為 props 中的值提供一個帶有驗證需求的對象,而不是一個字串數組。例如:
Vue.component('my-component', {
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字串
propC: {
type: String,
required: true
},
// 帶有默認值的數字
propD: {
type: Number,
default: 100
},
// 帶有默認值的對象
propE: {
type: Object,
// 對象或數組默認值必須從一個工廠函數獲取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函數
propF: {
validator: function (value) {
// 這個值必須匹配下列字串中的一個
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
當 prop 驗證失敗的時候,(開發環境構建版本的) Vue 將會產生一個控制臺的警告。
type 可以是下麵原生構造器:
String
Number
Boolean
Array
Object
Date
Function
Symbol
type 也可以是一個自定義構造器,使用 instanceof 檢測。
自定義事件
父組件是使用 props 傳遞數據給子組件,但如果子組件要把數據傳遞回去,就需要使用自定義事件!
我們可以使用 v-on 綁定自定義事件, 每個 Vue 實例都實現了事件介面(Events interface),即:
- 使用
$on(eventName)
監聽事件
- 使用
$emit(eventName)
觸發事件
另外,父組件可以在使用子組件的地方直接用 v-on 來監聽子組件觸發的事件。
以下實例中子組件已經和它外部完全解耦了。它所做的只是觸發一個父組件關心的內部事件。
實例
<div id="app">
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
</div>
<script>
Vue.component('button-counter', {
template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
incrementHandler: function () {
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
</script>
如果你想在某個組件的根元素上監聽一個原生事件。可以使用 .native 修飾 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
data 必須是一個函數
上面例子中,可以看到 button-counter 組件中的 data 不是一個對象,而是一個函數:
data: function () {
return {
count: 0
}
}
這樣的好處就是每個實例可以維護一份被返回對象的獨立的拷貝,如果 data 是一個對象則會影響到其他實例,如下所示:
實例
<div id="components-demo3" class="demo">
<button-counter2></button-counter2>
<button-counter2></button-counter2>
<button-counter2></button-counter2>
</div>
<script>
var buttonCounter2Data = {
count: 0
}
Vue.component('button-counter2', {
/*
data: function () {
// data 選項是一個函數,組件不相互影響
return {
count: 0
}
},
*/
data: function () {
// data 選項是一個對象,會影響到其他實例
return buttonCounter2Data
},
template: '<button v-on:click="count++">點擊了 {{ count }} 次。</button>'
})
new Vue({ el: '#components-demo3' })
</script>