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