# 組件詳解
>[success] 可在此處查看運(yùn)行文檔中的代碼示例結(jié)果:[https://github.com/jianyaoo/Vue](https://github.com/jianyaoo/Vue)
## 基本使用
> 我們?cè)谧?cè)一個(gè)組件的時(shí)候都會(huì)給組件起一個(gè)組件名,起組件名的兩種方式為`kebab-case`(全部都是小寫(xiě)字母,中間用-連接)和`PascalCase`(首字母大寫(xiě))。當(dāng)時(shí)用連字符的時(shí)候,可能使用連字符的方式進(jìn)行調(diào)用。如果使用首字母大小寫(xiě)的方式,兩種方式都可以調(diào)用。
### 全局注冊(cè)組件
**<span style="padding-top:0px;display:inline-block;">注冊(cè)方式</span>**
使用`Vue.component`方式注冊(cè)的組件都為全局注冊(cè)組件,全局注冊(cè)組件可以在任何新創(chuàng)建的Vue根實(shí)例模板中
**<span style="padding-top:20px;display:inline-block;">代碼實(shí)例</span>**
~~~html
<h3>全局注冊(cè)組件</h3>
<div>
<el-glob></el-glob>
</div>
~~~
~~~JavaScript
Vue.component('el-glob',{
template:"<div>hello , component</div>"
})
~~~
<div style="background:#333;color:#fff;padding:15px;">
運(yùn)行結(jié)果:
<div>
<h3>全局注冊(cè)組件</h3>
<div>hello , component</div>
</div>
</div>
### 實(shí)例內(nèi)注冊(cè)組件
**<span style="padding-top:0px;display:inline-block;">注冊(cè)方式</span>**
實(shí)例內(nèi)注冊(cè)即在Vue的實(shí)例內(nèi)使用`component`屬性進(jìn)行注冊(cè)的方式。
**<span style="padding-top:20px;display:inline-block;">代碼實(shí)例</span>**
~~~
<h3>實(shí)例內(nèi)注冊(cè)</h3>
<div>
<el-local></el-local>
</div>
~~~
~~~
// 聲明一個(gè)組件的屬性
var local = {
template: "<div>這是一個(gè)實(shí)例內(nèi)注冊(cè)的組件</div>"
}
// 在根實(shí)例中調(diào)用組件
var vm = new Vue({
el:"#app",
components:{
"el-local":local
}
})
~~~
<div style="background:#333;color:#fff;padding:15px;">
運(yùn)行結(jié)果:
<div>
<h3>實(shí)例內(nèi)注冊(cè)</h3>
<div>這是一個(gè)實(shí)例內(nèi)注冊(cè)的組件</div>
</div>
</div>
>[danger] component組件屬性定義在哪個(gè)實(shí)例中,組件才可以在哪個(gè)實(shí)例中使用。而且子組件之間不可以直接調(diào)用,如果需要在子組件中調(diào)用另外一個(gè)子組件,需要在調(diào)用組件的屬性中使用`component`屬性
### 特殊元素使用組件
**<span style="padding-top:0px;display:inline-block;">使用說(shuō)明</span>**
有一些元素內(nèi)只能使用特定的元素,例如`table`、`ul`、`ol`等,如果直接在這些元素內(nèi)使用組件,組件會(huì)渲染到父級(jí)外面從而得不到自己想要的效果。使用`is`屬性可以解決在這些特定組件上使用組件。
**<span style="padding-top:20px;display:inline-block;">代碼實(shí)例</span>**
~~~
<h3>特殊元素使用組件</h3>
<table>
<tbody is="el-glob">
</tbody>
</table>
~~~
~~~
Vue.component('el-glob',{
template:"<th><td>hello , component</td></th>"
})
~~~
<div style="background:#333;color:#fff;padding:15px;">
運(yùn)行結(jié)果:
<div>
<h3>特殊元素使用組件</h3>
<div>hello , component</div>
</div>
</div>
**<span style="padding-top:20px;display:inline-block;">代碼說(shuō)明</span>**
使用`is`后的代碼結(jié)構(gòu)如下:
```
<table>
<th>
<td>hello , component</td>
<th>
</table>
```
在不使用`is`時(shí)的代碼結(jié)構(gòu)為:
```
<th>
<td>hello , component</td>
<th>
<table>
<tbody></tbody>
</table>
```
### 帶數(shù)據(jù)的組件
**<span style="padding-top:0px;display:inline-block;">使用說(shuō)明</span>**
在組件模板中如果使用變量,需要在組件中單獨(dú)使用`data`屬性。需要說(shuō)明的是在組件中的`data`屬性不是一個(gè)對(duì)象,而是一個(gè)可以返回一個(gè)對(duì)象的函數(shù)。
**<span style="padding-top:20px;display:inline-block;">代碼實(shí)例</span>**
~~~
<h3>帶數(shù)據(jù)的組件</h3>
<div>
<my-component></my-component>
</div>
~~~
~~~
Vue.component('my-component' , {
data:function() {
return{
message:"這是一個(gè)帶數(shù)據(jù)的組件"
}
},
template:"<div>{{message}}</div>"
})
~~~
<div style="background:#333;color:#fff;padding:15px;">
運(yùn)行結(jié)果:
<div>
<h3>帶數(shù)據(jù)的組件</h3>
<div>這是一個(gè)帶數(shù)據(jù)的組件</div>
</div>
</div>
### 組件獨(dú)立數(shù)據(jù)
一個(gè)獨(dú)立組件的數(shù)據(jù),應(yīng)該聲明在組件內(nèi)部,只供當(dāng)前組件一個(gè)可以調(diào)用,而不能定義在組件外面。容易引起當(dāng)組件重復(fù)使用時(shí)發(fā)生錯(cuò)誤的情況,如下代碼所示:
~~~
<h3>組件獨(dú)立數(shù)據(jù)</h3>
<h5>反例</h5>
<div>
<el-data></el-data>
<el-data></el-data>
<el-data></el-data>
</div>
~~~
~~~
var data = {
counter:0
}
Vue.component("el-data",{
data:function() {
return data ;
},
template:"<button @click='counter++'>{{counter}}</button>"
})
~~~
<div style="background:#333;color:#fff;padding:15px;">
運(yùn)行結(jié)果:
當(dāng)點(diǎn)擊第一個(gè)按鈕時(shí),第二個(gè)按鈕的值和第三個(gè)按鈕的值都會(huì)發(fā)生改變。
</div>
正確的實(shí)現(xiàn)代碼應(yīng)該如下:
~~~
Vue.component("el-data",{
data:function() {
return {
counter:0
};
},
template:"<button @click='counter++'>{{counter}}</button>"
})
~~~
## 使用prop進(jìn)行傳值
通信組件即可以在不同的組件之間進(jìn)行傳值,傳值的方式是使用`prop`屬性。html中的屬性大小寫(xiě)不敏感,如果使用駝峰法命名的屬性在使用的時(shí)候需要用連接法。
### 字符串?dāng)?shù)組傳值
**<span style="padding-top:0px;display:inline-block;">簡(jiǎn)單傳值</span>**
~~~html
<h5>簡(jiǎn)單傳值</h5>
<div>
<el-props message="我是父級(jí)的參數(shù)" my-count="參數(shù)內(nèi)容"></el-props>
</div>
~~~
~~~
Vue.component("el-props" , {
props:["message","myCount"],
template:"<div>{{message}}+{{myCount}}</div>"
})
~~~
<div style="background:#333;color:#fff;padding:15px;">
運(yùn)行結(jié)果:
<h5>簡(jiǎn)單傳值</h5>
<div>我是父級(jí)的參數(shù)+參數(shù)內(nèi)容</div>
</div>
**<span style="padding-top:20px;display:inline-block;">動(dòng)態(tài)傳值</span>**
~~~
<h5>動(dòng)態(tài)傳值</h5>
<div>
<input type="text" v-model="parentMessage">
<el-props :message="parentMessage"></el-props>
</div>
~~~
~~~
Vue.component("el-props" , {
props:["message","myCount"],
template:"<div>{{message}}</div>"
})
~~~
<div style="background:#333;color:#fff;padding:15px;">
運(yùn)行結(jié)果:
div內(nèi)的內(nèi)容隨著輸入框中的內(nèi)容發(fā)生變化而變化
</div>
### 單向數(shù)據(jù)流
所有的數(shù)據(jù)流都使得prop的數(shù)據(jù)由父級(jí)向下的一個(gè)單項(xiàng)綁定流動(dòng):即父級(jí)prop的更新會(huì)向下流動(dòng)到子組件,但是子組件的prop更新不會(huì)影響到父級(jí)。這個(gè)就是prop數(shù)據(jù)的單向數(shù)據(jù)流。
>[info] 從父組件傳下來(lái)的prop,每次父組件發(fā)生更新時(shí),子組件的值都會(huì)自動(dòng)刷新到最新值。所以一般不應(yīng)該在子組件內(nèi)部修改prop的值。
存在兩種需要修改子組件prop的值得情況:
**<span style="padding-top:20px;display:inline-block;">prop作為初始值</span>**
如果子組件接受到prop值后希望將prop值作為一個(gè)自己的參數(shù)使用,傳遞過(guò)來(lái)的prop值只是作為一個(gè)初始值。這種情況下應(yīng)該在子組件內(nèi)部定義一個(gè)變量來(lái)接收該參數(shù)。
~~~
props:["counter"],
data:function(){
return {
count:this.counter
}
},
~~~
**<span style="padding-top:20px;display:inline-block;">作為一個(gè)初始值且需要對(duì)prop值進(jìn)行經(jīng)常變化</span>**
當(dāng)需要對(duì)prop值進(jìn)行一定的邏輯處理的時(shí)候,就需要定義一個(gè)計(jì)算屬性來(lái)接收prop值。
~~~
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
~~~
### prop驗(yàn)證
當(dāng)子組件接受到一個(gè)prop時(shí),可以對(duì)prop進(jìn)行驗(yàn)證,如果驗(yàn)證不通過(guò)的話會(huì)在控制臺(tái)打印出警告信息。主要用于開(kāi)發(fā)調(diào)試
~~~
Vue.component('my-component', {
props: {
// 基礎(chǔ)的類型檢查 (`null` 和 `undefined` 會(huì)通過(guò)任何類型驗(yàn)證)
propA: Number,
// 多個(gè)可能的類型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 帶有默認(rèn)值的數(shù)字
propD: {
type: Number,
default: 100
},
// 帶有默認(rèn)值的對(duì)象
propE: {
type: Object,
// 對(duì)象或數(shù)組默認(rèn)值必須從一個(gè)工廠函數(shù)獲取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗(yàn)證函數(shù)
propF: {
validator: function (value) {
// 這個(gè)值必須匹配下列字符串中的一個(gè)
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
~~~
## 插槽
- 第一篇 基礎(chǔ)篇
- 01 - 初始 vue
- 02 - 數(shù)據(jù)綁定
- 03 - 計(jì)算屬性
- 04 - v-bind及class與style綁定
- 05 - 內(nèi)置指令
- 06 - 表單與v-model
- 07 - 組件
- 08 - 自定義指令
- 文檔模板
- 第二篇 進(jìn)階篇
- 01 - Render函數(shù)
- 02 - webPack
- 03 - 插件
- 第三篇 實(shí)戰(zhàn)篇
- 01 - iview經(jīng)典組件剖析
- 02 - 知乎日?qǐng)?bào)項(xiàng)目開(kāi)發(fā)
- 03 - 電商網(wǎng)站開(kāi)發(fā)
- 04 - 相關(guān)開(kāi)源介紹
