vue.js——基礎篇之vue組件
一、什麼是組件
組件(Component)是Vue.js最強大的功能之一。組件可以擴展 HTML元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,vue.js的編譯器爲它添加特殊功能,在有些情況下,組件也可以是原生HTML元素的形式,以is特性擴展。組件系統讓我們可以用獨立可複用的小組件來構建大型應用,幾乎任意類型的應用的界面都可以抽象爲一個組件樹。
組件系統是Vue的另一個重要概念,因爲它是一種抽象,允許使用小型、獨立和通常可複用的組件構建大型應用。
在Vue裏,一個組件本質上是一個擁有預定義選項的一個Vue實例。
二、組件與自定義元素的關係
1、Vue組件非常類似於自定義元素,這是因爲Vue的組件語法部分參考了該規範。
2、 Web組件規範仍然處於草案階段,並且未被所有瀏覽器原生實現。相比之下,Vue組件不需要任何polyfill,並且在所有支持的瀏覽器 (IE9 及更高版本) 之下表現一致。必要時,Vue組件也可以包裝於原生自定義元素之內。
3、Vue組件提供了純自定義元素所不具備的一些重要功能,最突出的是跨組件數據流、自定義事件通信以及構建工具集成。
三、註冊全局組件
1、全局組件,所有實例都能用全局組件。
全局組件在註冊之後可以用在任何新創建的Vue根實例(new Vue)的模板中。
2、註冊全局組件
*註冊一個全局組件語法格式如下:
Vue.component(tagName, options)
*參數說明:
tagName爲組件名,options爲配置選項。
*註冊後,可使用以下方式來調用組件:
<tagName></tagName>
*注意:
組件在註冊後,便可在父實例的模塊中以自定義元素的形式使用,但要確保在初始化根實例之前註冊了組件。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>註冊全局組件</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<script>
//註冊全局組件
Vue.component('my-component',{
template:'<div>{{msg}}<input type="button" value="彈" @click="tanchu"/></div>',
//注意:這裏的data必須是一個函數,和實例中的data不一樣,return返回一個對象
data:function(){
return {
msg:"Hello vue"
};
},
methods:{
tanchu:function(){
console.log(this.msg);
}
}
});
//初始化根實例
new Vue({
el:"#app"
});
</script>
</body>
</html>
四、註冊局部組件
全局註冊往往是不夠理想的。全局註冊所有的組件意味着即便已經不再使用一個組件了,它仍然會被包含在
最終的構建結果中。這造成了用戶下載的JavaScript的無謂的增加。所以可以在實例選項中註冊局部組件,這
樣組件只能在這個實例中使用。
*註冊局部組件步驟:
1)通過一個普通的JavaScript對象來定義組件:
var ComponentA = { }
2)然後在根實例中的components選項中定義想要使用的組件:
new Vue({
el: ‘#app’,
components: {
‘component-a’: ComponentA
}
})
*對於components對象中的每個屬性來說,其屬性名就是自定義元素的名字,其屬性值就是這個組件的選項對象。
*注意局部註冊的組件在其子組件中不可用。例如,希望 ComponentA 在ComponentB中可用,則需要這樣寫:
var ComponentA = {};
var ComponentB = {
components: {
‘component-a’: ComponentA
},
}
*或者如果通過Babel和webpack使用ES2015模塊,那麼代碼看起來更像:
import ComponentA from ‘./ComponentA.vue’
export default {
components: {
ComponentA
},
}
*注意在ES2015+中,在對象中放一個類似ComponentA的變量名其實是ComponentA: ComponentA的縮寫,即這個變量名同時是用在模板中的自定義元素的名稱,包含了這個組件選項的變量名。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>註冊局部組件</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<div class="app">
<my-component></my-component>
</div>
<script>
//註冊局部組件
var com = {
template:'<div>{{msg}}<input type="button" value="彈" @click="tanchu"/></div>',
data:function(){
return {
msg:"Hello"
};
},
methods:{
tanchu:function(){
console.log(this.msg);
}
}
};
//初始化根實例
new Vue({
el:"#app",
components:{
'my-component':com
}
});
new Vue({
el:".app"
//第二個根實例沒有註冊my-component這個局部組件,會報錯
});
</script>
</body>
</html>
五、關於組件名的注意事項
在註冊一個組件時,始終需要給它一個名字。組件名就是 Vue.component 的第一個參數。當直接在DOM中使用一個組件 (而不是在字符串模板或單文件組件) 的時候,強烈推薦遵循W3C規範中的自定義組件名 (字母全小寫且必須包含一個連字符)。這會避免當前以及未來的HTML元素相沖突。請注意,Vue.js不對自定義標記名稱(全小寫,必須包含連字符)強制執行W3C規則,但按照此慣例被認爲是良好的做法。
定義組件名的方式有兩種:
1)使用kebab-case:Vue.component('my-component-name', {})
當使用kebab-case(短橫線分隔命名)定義一個組件時,也必須在引用這個自定義元素時使用kebab-case,
例如<my-component-name>。
2)使用PascalCase:Vue.component('MyComponentName', {})
當使用PascalCase(駝峯式命名)定義一個組件時,在引用這個自定義元素時兩種命名法都可以使用。
儘管如此,直接在DOM(即非字符串的模板)中使用時只有kebab-case是有效的。
六、模板解析
有些 HTML 元素,諸如 ul、ol、table,對於哪些元素可以出現在其內部是有嚴格限制的。而有些元素,諸如 li、tr,只能出現在其它某些特定的元素內部。這會導致使用這些有約束條件的元素時遇到一些問題。這時候自定義組件會被作爲無效的內容提升到外部,並導致最終渲染結果出錯。
is 特性給了一個變通的辦法:
<table>
<tr is=”blog-post-row”></tr>
</table>
需要注意的是如果從以下來源使用模板的話,這條限制是不存在的:
1)字符串 (例如:template: ‘…’)
2)單文件組件 (.vue)
3)<script type=”text/x-template”>
這些限制中最常見的是:
- a不能包含其他交互元素(例如按鈕和其他鏈接)
- li應該是直接孩子ul或ol,兩者ul並ol只能包含li
- option應該是一個直接的孩子select,並且select只能包含option(和optgroup)
- table只能包含thead,tbody,tfoot和tr,這些元素應該是直接孩子table
- tr只能包含th和td,而這些元素應該是直接子女的tr
七、組件通訊
1、Prop
prop是父組件用來傳遞數據的一個自定義屬性。父組件的數據需要通過props把數據傳給子組件,
子組件需要顯式地用props選項聲明"prop":Prop是可以在組件上註冊的一些自定義特性。當一個值
傳遞給一個prop特性的時候,它就變成了那個組件實例的一個屬性。
2、靜態的Prop
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>靜態Prop</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<tip msg="HelloHtml"></tip>
<tip msg="HelloCss"></tip>
<tip msg="HelloJavascript"></tip>
</div>
<script type="text/x-Template" id="tipTpl">
<div>
<input type="button" value="消息彈窗" @click="alterMsg"/>
</div>
</script>
<script>
var tipTpl = {
template:'#tipTpl',
//聲明prop
props:['msg'],
methods:{
alterMsg:function(){
console.log(this.msg);
}
}
};
new Vue({
el:"#app",
components:{
'tip':tipTpl
}
});
</script>
</body>
</html>
3、動態的Prop
可以用v-bind動態綁定props的值到父組件的數據中。每當父組件的數據變化時,該變化也會傳導給子組件。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>動態Prop</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<tip v-bind:msg="a"></tip>
<tip msg="HelloCss"></tip>
<tip msg="HelloJavascript"></tip>
</div>
<script type="text/x-Template" id="tipTpl">
<div>
<input type="button" value="消息彈窗" @click="alterMsg"/>
</div>
</script>
<script>
var tipTpl = {
template:'#tipTpl',
//聲明prop
props:['msg'],
methods:{
alterMsg:function(){
console.log(this.msg);
}
}
};
new Vue({
el:"#app",
components:{
'tip':tipTpl
},
data:{
a:'HelloVue'
}
});
</script>
</body>
</html>
一個組件默認可以擁有任意數量的 prop,任何值都可以傳遞給任何 prop。在上述模板中,你會發現我們能夠在組件實例中訪問這個值,就像訪問 data 中的值一樣。
一個 prop 被註冊之後,你就可以像這樣把數據作爲一個自定義特性傳遞進來:
然而在一個典型的應用中,你可能在 data 裏有一個博文的數組:
new Vue({
el: ‘#blog-post-demo’,
data: {
posts: [
{ id: 1, title: ‘My journey with Vue’ },
{ id: 2, title: ‘Blogging with Vue’ },
{ id: 3, title: ‘Why Vue is so fun’ },
]
}
})
並想要爲每篇博文渲染一個組件: