基礎(chǔ)示例
組件是可復(fù)用的 Vue 實(shí)例,所以它們與 new Vue 接收相同的選項(xiàng),例如 data、computed、watch、methods 以及生命周期鉤子等。僅有的例外是像 el 這樣根實(shí)例特有的選項(xiàng)。
組件的復(fù)用
你可以將組件進(jìn)行任意次數(shù)的復(fù)用:
- data必須是個(gè)函數(shù)
當(dāng)我們定義這個(gè) <button-counter> 組件時(shí),你可能會(huì)發(fā)現(xiàn)它的 data選項(xiàng)必須是一個(gè)函數(shù),
因此每個(gè)實(shí)例可以維護(hù)一份被返回對(duì)象的獨(dú)立的拷貝
通過prop向子組件傳遞數(shù)據(jù)
Prop 是你可以在組件上注冊(cè)的一些自定義特性。當(dāng)一個(gè)值傳遞給一個(gè) prop 特性的時(shí)候,它就變成了那個(gè)組件實(shí)例的一個(gè)屬性。為了給博文組件傳遞一個(gè)標(biāo)題,我們可以用一個(gè) props 選項(xiàng)將其包含在該組件可接受的 prop 列表中:
單個(gè)根元素
一個(gè)組件里,只能有一個(gè)根元素,負(fù)責(zé)會(huì)報(bào)錯(cuò)
通過事件向父組件發(fā)送消息
我們可以調(diào)用內(nèi)建的 $emit 方法并傳入事件的名字,來向父級(jí)組件觸發(fā)一個(gè)事件。
這里需要注意的是:父類組件綁定的事件名大小寫不敏感的,但是在子組件里發(fā)送消息時(shí)必須要使用全部小寫的方式發(fā)送消息,否則無法成功發(fā)送消息。比如:父組件綁定事件v-on:myPlay="playGame",子組建立調(diào)用時(shí)就是:$emit("myplay"),或者父子組件的事件名都是帶短線的寫法也是可以的。
- 使用事件拋出一個(gè)值
可以使用 emit 的第二個(gè)參數(shù)來提供這個(gè)值。例如:emit("myplay","play football")。然后當(dāng)在父級(jí)組件監(jiān)聽這個(gè)事件的時(shí)候,我們可以通過$event訪問到被拋出的這個(gè)值:
*組件上使用v-model
插槽分發(fā)內(nèi)容
Vue 自定義的 <slot> 元素可以實(shí)現(xiàn)插槽分發(fā)內(nèi)容
動(dòng)態(tài)組件
你可以在這里查閱并體驗(yàn)完整的代碼,或在這個(gè)版本了解綁定組件選項(xiàng)對(duì)象,而不是已注冊(cè)組件名的示例。
示例代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>組件基礎(chǔ)</title>
<script src="../static/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<!--組件是可復(fù)用的 Vue 實(shí)例,且?guī)в幸粋€(gè)名字:在這個(gè)例子中是 <button-counter>。
我們可以在一個(gè)通過 new Vue 創(chuàng)建的 Vue 根實(shí)例中,把這個(gè)組件作為自定義元素來使用:
因?yàn)榻M件是可復(fù)用的 Vue 實(shí)例,所以它們與 new Vue 接收相同的選項(xiàng),例如 data、computed、
watch、methods 以及生命周期鉤子等。僅有的例外是像 el 這樣根實(shí)例特有的選項(xiàng)。-->
<button-counter></button-counter>
<br />
<!--組件的復(fù)用:
你可以將組件進(jìn)行任意次數(shù)的復(fù)用:
注意當(dāng)點(diǎn)擊按鈕時(shí),每個(gè)組件都會(huì)各自獨(dú)立維護(hù)它的 count。
因?yàn)槟忝坑靡淮谓M件,就會(huì)有一個(gè)它的新實(shí)例被創(chuàng)建。-->
<button-counter></button-counter>
<button-counter></button-counter>
<!--data 必須是一個(gè)函數(shù)
當(dāng)我們定義這個(gè) <button-counter> 組件時(shí),你可能會(huì)發(fā)現(xiàn)它的 data選項(xiàng)必須是一個(gè)函數(shù),
因此每個(gè)實(shí)例可以維護(hù)一份被返回對(duì)象的獨(dú)立的拷貝:-->
<!--組件的組織:
通常一個(gè)應(yīng)用會(huì)以一棵嵌套的組件樹的形式來組織:
例如,你可能會(huì)有頁(yè)頭、側(cè)邊欄、內(nèi)容區(qū)等組件,每個(gè)組件又包含了其它的像導(dǎo)航鏈接、博文之類的組件。
為了能在模板中使用,這些組件必須先注冊(cè)以便 Vue 能夠識(shí)別。這里有兩種組件的注冊(cè)類型:全局注冊(cè)和
局部注冊(cè)。至此,我們的組件都只是通過 Vue.component 全局注冊(cè)的:-->
<!--通過 Prop 向子組件傳遞數(shù)據(jù)-->
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
<!--
作者:zzhrainbow@163.com
時(shí)間:2018-07-22
描述:在一個(gè)典型的應(yīng)用中,你可能在 data 里有一個(gè)博文的數(shù)組:
-->
<blog-post v-for="post in posts" v-bind:title="post.title" v-bind:key="post.id"></blog-post>
<!--通過事件向父級(jí)組件發(fā)送消息:
在我們開發(fā) <blog-post> 組件時(shí),它的一些功能可能要求我們和父級(jí)
組件進(jìn)行溝通。例如我們可能會(huì)引入一個(gè)可訪問性的功能來放大博文的字號(hào),
同時(shí)讓頁(yè)面的其它部分保持默認(rèn)的字號(hào)。在其父組件中,我們可以通過添加一個(gè)
postFontSize 數(shù)據(jù)屬性來支持這個(gè)功能:-->
<div v-bind:style="{fontSize:postFontSize + 'em'}">
<blog-post-elements v-for="post in postElements" v-bind:post="post" v-bind:key="post.id" v-on:changeBigText="changeFontSize($event)">
</blog-post-elements>
</div>
<!--使用事件拋出一個(gè)值
有的時(shí)候用一個(gè)事件來拋出一個(gè)特定的值是非常有用的。例如我們可能想讓 <blog-post>
組件決定它的文本要放大多少。這時(shí)可以使用 $emit 的第二個(gè)參數(shù)來提供這個(gè)值:-->
<!--通過插槽分發(fā)內(nèi)容:
和 HTML 元素一樣,我們經(jīng)常需要向一個(gè)組件傳遞內(nèi)容,像這樣:
幸好,Vue 自定義的 <slot> 元素讓這變得非常簡(jiǎn)單:-->
<alert-box>
Something bad happened.
</alert-box>
<!--動(dòng)態(tài)組件:
可以通過 Vue 的 <component> 元素加一個(gè)特殊的 is 特性來實(shí)現(xiàn):-->
<button v-for="tab in tabs" v-bind:key="tab" v-bind:class="['tab-button', { active: currentTab === tab }]" v-on:click="currentTab = tab">{{ tab }}</button>
<component v-bind:is="currentTabComponent" class="tab"></component>
</div>
<script type="text/javascript">
Vue.component("buttonCounter", {
data() {
return {
count: 0,
}
},
template: "<button v-on:click='count++'>you clicked me {{count}} times</button>"
})
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
Vue.component('blog-post-elements', {
props: ['post'],
template: '<div ><h3>{{ post.title }}</h3> <button v-on:click="enlargeText" > enlarge text </button> <div v-html="post.content" > </div></div>',
methods: {
enlargeText() {
this.$emit("changebigtext", 0.3) //注意這里的傳送事件與父組件里監(jiān)聽的事件名字的區(qū)別
}
},
})
Vue.component('alert-box', {
template: "<div class='demo - alert - box '><strong>Error!</strong><slot></slot> </div>"
})
Vue.component('tab-home', {
template: '<div>Home component</div>'
})
Vue.component('tab-posts', {
template: '<div>Posts component</div>'
})
Vue.component('tab-archive', {
template: '<div>Archive component</div>'
})
var vm = new Vue({
el: "#app",
data: {
posts: [{
id: 1,
title: "first blog",
},
{
id: 2,
title: "second blog",
},
{
id: 3,
title: "third blog",
},
],
postFontSize: 1,
postElements: [{
id: 2016,
content: "<p>1.為了變大數(shù)據(jù)</p>",
},
{
id: 2017,
content: "<p>2.第二條</p>",
},
{
id: 2018,
content: "<p>3.第三條來了</p>",
},
],
currentTab: 'Home',
tabs: ['Home', 'Posts', 'Archive']
},
methods: {
changeFontSize(changeValue) {
this.postFontSize += changeValue
}
},
computed: {
currentTabComponent() {
return "tab-" + this.currentTab.toLowerCase()
}
}
})
</script>
<style type="text/css">
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: lightgray;
}
.tab-button.active {
background: lightgray;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
background: lightpink;
}
</style>
</body>
</html>
運(yùn)行效果:

參考:
vue.js 組件基礎(chǔ)