十,元件
使用元件
注冊
可以通過以下這種方式建立一個Vue執行個體
new Vue({
el: '#some-element',
})
注冊一個全局元件,你可以使用Vue.component(tagName,options)
Vue.component('my-component',{ })
在父執行個體的子產品中以自定義元素 <my-component></my-component> 的形式使用
<div id="example">
<my-component></my-component>
</div>
// 注冊
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
// 建立根執行個體
new Vue({
el:'#example'
})
渲染為
<div id="example">
<div>A custom component!</div>
</div>
複制
局部注冊
使用元件執行個體選項注冊,可以使元件僅在另一個執行個體/元件的作用域中可用
var Child = {
template:'<div>A custom component !</div>'
}
new Vue({
components: {
'my-component':Child
}
})
複制
data 必須是函數
使用元件時,大多數選項可以被傳入到Vue 構造器中,有一個列外,data 必須是函數。
Vue.component('my-component', {
template: '<span> {{ message}}</span>',
data: {
message: 'hello'
}
})
複制
Vue 會在控制台發出警告,告訴你在元件中 data 必須是一個函數
var data = { counter:0}
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data: function () {
return data
}
})
new Vue({
el: '#example-2'
})
複制
三個元件共享了同一個 data
data: function() {
retrun {
counter: 0
}
}
複制
構成元件
Prop
使用Prop傳遞資料,元件的作用域是孤立的,意味着不能并且不應該再子元件的
模闆内引用父元件的資料,可以使用props 把資料傳給子元件。
prop 是父元件用來傳遞資料的一個自定義屬性,子元件需要顯示的用props
Vue.component('child', {
// 聲明 props
props: ['message'],
// 像 data 一樣 prop 可以用在模闆内
// 同樣也可以在 vm 執行個體中像 “this.message”這樣使用
templae: '<span>{{ message }}</span>'
})
複制
然後向它傳入一個普通字元串:
<child message="hello!"></child>
結果:
hello!
camelCase vs.kebab-case
HTML 特性不區分大小寫 當使用非字元串模闆的時,prop 的名字形式會從camelCase 轉為
kebab-case(短橫線隔開)
Vue.component('child', {
props:['myMessage'],
template: '<span>{{ myMessage}}</span>'
})
<child my-message="hello"></child>
複制
動态Prop
類似用于v-bind 綁定 HTML 特性到一個表達式,也可以用v-bind 動态綁定props的值
到父元件的資料中。沒當父元件的資料變化時,該變化也會傳導給子元件。
<div>
<input v-model="paremtMsg">
<child v-bind:my-message="parentMsg"></child>
</div>
複制
使用 v-bind 的縮寫文法統稱更簡單。
<child :my-message="parentMsg"></child>
字面量文法 vs 動态文法
// 實際傳遞參數
<comp v-bind:some-prop="1"></comp>
單向資料流
1.prop 作為初始值傳入,子元件之後隻是将它的初始值作為本地資料的初始值使用;
2.prop 作為需要被轉變的原始值傳入。
定義一個局部的 data 屬性 ,并将prop 的初始值作為局部資料的初始值。
props:['initialCounter'],
data: function () {
return { counter: this.initialCounter}
}
定義一個computed 屬性。此屬性從prop 的值計算出來。
props:['size'],
computed: {
normalizedSize: function() {
return this.size.trim().toLowerCase()
}
}
複制
Prop 驗證
元件也可以為props指定驗證請求,prop 是一個對象而不是字元串數組時,它包含驗證要求:
Vue.component('example', {
props: {
// 基礎類型檢測 (`null` 意思是任何類型都可以)
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 value > 10
}
}
}
})
複制
自定義事件
子元件需要把資料傳回父元件,需要自定義事件。
使用v-on 綁定自定義事件。
使用 $on(eventName) 監聽事件
使用 $emit(eventName) 觸發事件
給元件綁定原生事件
可以使用 .native 修飾 v-on
<my-component v-on:click.native="doTheThing"></my-component>
使用自定義元件的表單輸入元件
自定義事件也可以用來建立自定義的表單輸入元件,使用 v-model 來進行資料雙向綁定。
<input v-model="something">
非父子元件通信
有時候非父子關系的元件也需要通信,在簡單的場景下,使用個空的Vue 執行個體作為中央事件總線。
var bus = new Vue()
// 觸發元件 A 中的事件
bus.$emit('id-selected', 1)
// 在元件 B 建立的鈎子中監聽事件
bus.$on('id-selected', function(id) {
//...
})
複制
使用Slot 分發内容
在使用元件的時候,我們常常遇到這樣組合。
<app>
<app-header></app-header>
<app-footer></app-footer>
</app>
複制
注意兩點:
1.<app> 元件不知道它的挂載點有什麼内容,挂載點的内容是由<app>的父元件決定的
2.元件很有可能有它自己的模闆。
分發内容是在父元件作用域内編譯。
單個Slot
除非子元件模闆至少包含一個<slot>插口, 否則父元件的内容将會被丢棄。當子模闆隻有
一個沒有屬性的Slot 時,父元件整個内容片斷将插入到slot 所在的DOM位置,并沒替換掉
slot 标簽本身。
假定 my-component 元件有下面模闆:
<div>
<h2>我是子元件的标題</h2>
<slot>
隻有在沒有要分發的内容時才會顯示。
</slot>
</div>
複制
父元件模版:
<div>
<h1>我是父元件的标題</h1>
<my-component>
<p>這是一些初始内容</p>
<p>這是更多的初始内容</p>
</my-component>
</div>
複制
渲染結果:
<div>
<h1>我是父元件的标題</h1>
<div>
<h2>我是子元件的标題</h2>
<p>這是一些初始内容</p>
<p>這是更多的初始内容</p>
</div>
</div>
複制
具名 Slot
<slot> 元素可以用一個特殊的屬性 neme 來配置如何分發内容。多個slot 可以有不同的名字,具名solt 将比對的内容片段中有對應的slot 特殊的元素
仍然可以有個匿名slot,它是預設slot, 作為找不到比對的内容片斷的備用插槽。如果沒有預設的slot 這個找不到比對的内容将會被丢棄。
例如,假定我們有一個 app-layout 元件,它的模闆為:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
複制
父元件模版:
<app-layout>
<h1 slot="header">這裡可能是一個頁面标題</h1>
<p>主要内容的一個段落。</p>
<p>另一個主要段落。</p>
<p slot="footer">這裡有一些聯系資訊</p
</app>
複制
渲染結果為:
<div class="container">
<header>
<h1>這裡可能是一個頁面标題</h1>
</header>
<main>
<p>主要内容的一個段落。</p>
<p>另一個主要段落。</p>
</main>
<footer>
<p>這裡有一些聯系資訊</p>
</footer>
</div>
複制
動态元件
多個元件可以使用同一個挂載點,然後動态地在它們之間切換。使用保留的 <component> 元素,動态地綁定到它的 is 特性:
var vm = new Vue({
el: '#example',
data: {
currentView: 'home'
},
components: {
home: { /* ... */ },
posts: { /* ... */ },
archive: { /* ... */ }
}
})
<component v-bind:is="currentView">
<!-- 元件在 vm.currentview 變化時改變! -->
</component>
也可以直接綁定到元件對象上:
var Home = {
template: '<p>Welcome home!</p>'
}
var vm = new Vue({
el: '#example',
data: {
currentView: Home
}
})
複制
#keep-alive
如果把切換出來的的元件保留在記憶體中,可以保留它的狀态或避免重新渲染。
<keep-alive>
<component :is="currentView">
// 非活動元件将被緩存
</component>
</keep-alive>
複制
雜項
編寫可複用元件
可複用元件應當定義一個清晰的公開接口。
Vue 元件的 API 來自三部分 - props, events 和 slots :
Props 允許外部環境傳遞資料額給元件。
Events 允許元件觸發外部環境的副作用。
Slots 允許外部環境将額外的内容組合在元件中。
使用 v-bind 和 v-on 的簡寫文法,模闆的縮進清楚且簡潔:
<my-component
:foo = "baz"
:bar = "qux"
@event-a ="doThis"
@event-b="doThat"
>
<img slot="icon" src="...">
<p slot="main-text"></p>
</my-component>
複制
#子元件索引
可以使用ref 為子元件指定一個索引ID 例如:
<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({
el: '#parent'
})
// 通路子元件
var child = parent.$refs.profile
複制
當 ref 和 v-for 一起使用時, ref 是一個數組或對象,包含相應的子元件