what is component
組件是Vue.js最強(qiáng)大的功能之一.組件可以擴(kuò)展HTMl元素,封裝可重用的代碼.在較高層面上,組件是自定義元素,Vue.js的編譯器為它添加特殊功能.在有些情況下,組件也可以是原生HTML元素的形式,以 'is' 特性擴(kuò)展.
how to use
注冊(cè)全局組件
Vue.component('kai', {
template: '<div>我是全局組件</div>'
})
var app = new Vue({
el: "#app"
})
一定要在初始化跟實(shí)例(app)之前注冊(cè)組件,否則無效
注冊(cè)完之后就可以在dom中跟html元素的使用方式一樣的使用
<div id="app">
<kai></kai>
</div>
注冊(cè)局部組件
var app = new Vue({
el: "#app",
components: {
"localCom": {
template: "<p>我系局部組件</p>"
}
}
})
- 通過使用組件實(shí)例選項(xiàng)(components)注冊(cè)可以是組件僅在另一個(gè)實(shí)例/組件的作用域中可用
- 上邊注冊(cè)的組件 'localCom' 使用駝峰式命名,在使用時(shí) 要在每一個(gè)駝峰處使用 '-' 隔開
使用方式:
<div id="app">
<kai></kai>
<local-com></local-com>
</div>
is特性
由于Vue只有在瀏覽器解析和標(biāo)準(zhǔn)化HTML后才能獲取模板內(nèi)容.比如<ul>中只可以直接包裹<li>所以當(dāng)你像下邊這樣使用組件
<ul>
<my-component></my-component>
</ul>
瀏覽器會(huì)在Vue解析模板之前,標(biāo)準(zhǔn)化HTML,就會(huì)導(dǎo)致一些問題
變通的方案是使用特殊的 is 屬性:
<ul>
<li is="my-component"></li>
</ul>
data 必須是函數(shù)
在自定義組件中data選項(xiàng)必須是函數(shù),其實(shí)不難理解,如果你像Vue跟實(shí)例那樣,在自定義組件中也直接使用對(duì)象的形式,那么如果這個(gè)組件被多個(gè)地方使用,而data是一個(gè)對(duì)象,在內(nèi)存中就是同一個(gè)內(nèi)存空間,那如果在某一個(gè)地方修改data中的內(nèi)容,那其他的地方的組件數(shù)據(jù)也會(huì)一起改變,顯然是不合理的,所以data要是一個(gè)函數(shù),然后返回一個(gè)對(duì)象.
Vue.component("my-component", {
template: "<span>{{message}}</span>"
data: function () {
return {
message: "我是自定義全局組件"
}
}
}
)
組件間通訊
在Vue中,父子組件的關(guān)系可以總結(jié)為 props down, events up, 父組件通過props向下傳遞數(shù)據(jù)給子組件,子組件通過events給父組件發(fā)送消息.看下圖
1. 父 -> 子
組件實(shí)例的作用域是孤立的.這意味著不能(也不應(yīng)該)在子組件的模板內(nèi)直接 引用父組件的數(shù)據(jù).要讓子組件使用粗組件的數(shù)據(jù),我們需要這樣做:
<div id="app">
<kai msg="niguanwo"></kai>
<local-com></local-com>
</div>
Vue.component('kai', {
template: '<div>我是全局組件{{msg}}</div>',
props: ["msg"]
});
- HTMl特性是不區(qū)分大小寫的,所以當(dāng)使用的不是字符串模板, 駝峰式命名的 prop 需要轉(zhuǎn)換為相對(duì)應(yīng)的 短橫線隔開式命名
2.動(dòng)態(tài)綁定props
<div id="app">
<input type="text" v-model="time">
<kai msg="niguanwo" v-bind:timer="time"></kai>
<local-com></local-com>
</div>
<script src="./vue.js"></script>
<script>
// 注冊(cè)全局組件
Vue.component('kai', {
template: '<div>我是全局組件{{msg}}時(shí)間{{timer}}</div>',
props: ["msg", "timer"]
});
var app = new Vue({
el: "#app",
components: {
"localCom": {
template: "<p>我系局部組件</p>"
}
},
data: {
time: "jidianl"
}
})
</script>
- 這樣,父組件你的time只要變化,子組件的timer也會(huì)動(dòng)態(tài)的跟著改變
3.還可以直接傳遞一個(gè)對(duì)象,寫法如下
<div id="app">
<input type="text" v-model="time">
<kai v-bind="obj" v-bind:object="obj1"></kai>
<local-com></local-com>
</div>
<script src="./vue.js"></script>
<script>
// 注冊(cè)全局組件
Vue.component('kai', {
template: '<div>{{name}}{{age}}{{object.status}}{{object.year}}</div>',
props: ["name", "age", "object"]
});
var app = new Vue({
el: "#app",
data: {
obj: {
name: "kai",
age: 25
},
obj1: {
status: "ok",
year: "2017"
}
}
})
</script>
- 還是要在props顯示地寫出要接收的屬性的名稱,直接使用 v-bind="obj"
4.單向數(shù)據(jù)流
prop 是單向綁定的:當(dāng)父組件的屬性變化時(shí)聪舒,將傳導(dǎo)給子組件鼠哥,但是不會(huì)反過來坚踩。另外,每次父組件更新時(shí)偿短,子組件的所有 prop 都會(huì)更新為最新值。這意味著你不應(yīng)該在子組件內(nèi)部改變 prop佳遂。
如果需要修改使用下面兩種方式:
1. 定義一個(gè)局部變量落恼,并用 prop 的值初始化它:
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
-
定義一個(gè)計(jì)算屬性,處理 prop 的值并返回扯再。
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
5.非props特性
- 所謂非prop特性,就是它可以直接傳入組件,而不需要定義相應(yīng)的prop.
<bs-date-input data-3d-date-picker="true"></bs-date-input>
上邊這個(gè)會(huì)直接在bs-date-input的組件內(nèi)添加一個(gè)data-3d-date-picker的值為true不過需要在data返回的對(duì)象中聲明一個(gè)data-3d-date-picker屬性,并初始化一個(gè)默認(rèn)值出來
6.替換/覆蓋現(xiàn)有的特性
- 對(duì)于多數(shù)特性來說芍耘,傳遞給組件的值會(huì)覆蓋組件本身設(shè)定的值。即例如傳遞 type="large" 將會(huì)覆蓋 type="date" 且有可能破壞該組件熄阻!所幸我們對(duì)待 class 和 style 特性會(huì)更聰明一些斋竞,這兩個(gè)特性的值都會(huì)做合并操作,生成最終的值.
子 -> 父
1. 使用v-on綁定自定義事件
- v-on:aaa 也可簡(jiǎn)寫成 @aaa
- 父組件可以在使用子組件的地方直接用 v-on 來監(jiān)聽子組件觸發(fā)的事件。
2. 給組件綁定原生事件
<my-component v-on:click.native="doTheThing"></my-component>
- v-on:click.native 會(huì)監(jiān)聽組件所在的根實(shí)例的(app)doTheThing事件
3. sync 實(shí)現(xiàn)子父組件數(shù)據(jù)同步
4.其他
- 盡管有 props 和 events秃殉,但是有時(shí)仍然需要在 JavaScript 中直接訪問子組件坝初。為此可以使用 ref 為子組件指定一個(gè)索引 ID浸剩。|
<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({ el: '#parent' })
// 訪問子組件
var child = parent.$refs.profile