vue的核心基礎就是組件的使用,玩好了組件才能將前面學的基礎更好的運用起來。組件的使用更使咱們的項目解耦合。更加符合vue的設計思想MVVM。javascript
// 定義一個名爲 button-counter 的新組件 Vue.component('button-counter', { data: function () { return { count: 0 } }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' })
組件是可複用的 Vue 實例,且帶有一個名字:在這個例子中是 <button-counter>
。咱們能夠在一個經過 new Vue
建立的 Vue 根實例中,把這個組件做爲自定義元素來使用:css
<div id="components-demo"> <button-counter></button-counter> </div> new Vue({ el: '#components-demo' })
由於組件是可複用的 Vue 實例,因此它們與 new Vue
接收相同的選項,例如 data
、computed
、watch
、methods
以及生命週期鉤子等。僅有的例外是像 el
這樣根實例特有的選項。html
能夠將組件進行任意次數的複用:vue
<div id="components-demo"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
點擊按鈕時,每一個組件都會各自獨立維護它的count。由於你每用一次組件,都會有它的新實例被建立。html5
定義這個 <button-counter>
組件時,你可能會發現它的 data
並非像這樣直接提供一個對象:java
data: { count: 0 }
取而代之的是,一個組件的 data
選項必須是一個函數,所以每一個實例能夠維護一份被返回對象的獨立的拷貝:node
data: function () { return { count: 0 } }
若是 Vue 沒有這條規則,點擊一個按鈕就可能會影響到其它全部實例。app
一般一個應用會以一棵嵌套的組件樹的形式來組織:ide
例如,你可能會有頁頭、側邊欄、內容區等組件,每一個組件又包含了其它的像導航連接、博文之類的組件。函數
爲了能在模板中使用,這些組件必須先註冊以便 Vue 可以識別。這裏有兩種組件的註冊類型:全局註冊和局部註冊。
經過 Vue.component
全局註冊:
Vue.component('my-component-name', { // ... options ... })
全局註冊的組件能夠用在其被註冊以後的任何 (經過 new Vue
) 新建立的 Vue 根實例,也包括其組件樹中的全部子組件的模板中。
<body> <div id="app"></div> <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> // 聲明頭部組件 var Vheader = { template: ` <header class="head"> 我是頭部 </header> ` }; // 1.聲明入口組件 /* 1.頭部組件 2.側邊欄 3.內容組件 4.腳本組件 */ var Vmain = { template: ` <div class="main"> 我是入口 <Vheader></Vheader> </div> `, components:{ // 掛載子組件 Vheader, // 等價於Vheader:Vheader } }; new Vue({ el: '#app', // 3.使用子組件 template: `<Vmain/>`, // 單閉合 data: { }, components: { // 2.聲明變量,掛載子組件 Vmain: Vmain } }); </script> </body>
顯示效果以下所示:
注意:先聲明子組件、再掛載子組件、最後使用子組件。
<head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> * { padding: 0; margin: 0; } .main { width: 100%; } body { color: #fff; } .head { width: 100%; height: 70px; background-color: purple; text-align: center; font-size: 20px; line-height: 70px; } .wrap { width: 100%; height: 1200px; } .wrap .aside { width: 30%; height: 1200px; background-color:green; float: left; /*側邊欄浮動*/ } .wrap .content { width: 70%; height: 1200px; background-color: saddlebrown; float: left; /*內容區浮動*/ } </style> </head> <body> <div id="app"> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> // 打油詩:先聲子再掛子再用子 var Vheader = { // 先聲明頭部組件 template:` <header class="head"> 我是頭部 </header> ` }; var Vaside = { // 聲明側邊欄組件 template:` <div class="aside"> 我是側邊欄 </div> ` }; var Vcontent = { // 聲明內容區組件 template:` <div class="content"> 我是內容區域 </div> ` }; // 第一步.聲明入口組件 /* 1.頭部組件 2.側邊欄 3.內容組件 4.腳步組件 以上組件分別掛載到入口組件裏面去。 */ var Vmain = { // 局部組件 template:` <div class='main'> <Vheader></Vheader> <div class="wrap"> <Vaside/> <Vcontent/> </div> </div> `, components:{ // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫: Vheader, // 掛載子組件:頭部組件 Vaside, // 掛載子組件:側邊欄組件 Vcontent } }; new Vue({ el:"#app", // 注意一個vue裏面只有一個el //第三步.使用子組件 template:"<Vmain></Vmain>", data: { }, components:{ //第二步.聲明變量,掛載子組件 key表示組件名 value表示組件對象 Vmain:Vmain } }); </script> </body>
組件是可複用的Vue實例,而且帶有一個名字:在這個例子中是 <Vheader>
。咱們能夠在一個經過 new Vue
建立的 Vue 根實例中,把這個組件做爲自定義元素來使用。
顯示效果以下:
組件使用打油詩:1.聲子 2.掛子 3.用子。
<!-- 1.聲子 --> var App = { template:` <div class='app'></div> ` }; <!-- 2.掛子 --> new Vue({ el:"#app", template:"<App/>" components:{ App } })
Prop 是你能夠在子組件上註冊的一些自定義特性。當一個值傳遞給一個 prop 特性的時候,它就變成了那個組件實例的一個屬性。那麼就能夠像訪問data中的值同樣來訪問。
爲了給博文組件傳遞一個標題,咱們能夠用一個 props
選項將其包含在該組件可接受的 prop 列表中:
// 全局組件 Vue.component('blog-post', { props: ['title'], template: '<h3>{{ title }}</h3>' })
一個組件默承認以擁有任意數量的 prop,任何值均可以傳遞給任何 prop。在上述模板中,你會發現咱們可以在組件實例中訪問這個值,就像訪問 data
中的值同樣。
一個 prop 被註冊以後,你就能夠像這樣把數據做爲一個自定義特性傳遞進來:
<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>
<script type="text/javascript"> var Vheader = { // 先聲明頭部組件 template:` <header class="head"> <h3>{{title}}</h3> // 模板語法渲染title <span>{{count}}</span> <button @click = 'count+=1'>點擊</button> </header> `, data(){ return { count: 0 } }, props:['title'], // props接收title methods:{ } }; var Vmain = { // 局部組件 template:` <div class='main'> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent/> </div> </div> `, components:{ // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫: Vheader, // 掛載子組件:頭部組件 Vaside, // 掛載子組件:側邊欄組件 Vcontent }, props:['title'] // 自定義的屬性 }; new Vue({ el:"#app", // 注意一個vue裏面只有一個el //第三步.使用子組件 template:"<Vmain v-bind:title='text'/>", // title是屬性名,'text'是數據屬性的名字 data: { text:"alex是SB" // 在data中設置text,這是數據 }, components:{ //第二步.掛載子組件 key表示組件名 value表示組件對象 Vmain:Vmain } }); </script>
顯示效果以下所示:
props:['自定義的屬性']
當一個值傳遞給一個prop特性的時候,它就變成了那個組件實例的一個屬性,能夠像訪問data中的值同樣。
須要綁定自定義的屬性<Vheader :title = '父組件中data聲明的數據屬性'/>
一個組件默承認以擁有任意數量的prop,任何值均可以傳遞任何prop。
在上述模板中,會發現咱們可以在組件實例中訪問這個值,就像訪問data中的值同樣。
<script type="text/javascript"> var Vcontent = { // 聲明內容區組件 template:` <div class="content"> <ul> <li v-for="post in posts" :key="post.id"> // 對應id <h3>個人博客標題:{{post.title}}</h3> <p>個人博客內容:{{post.content}}</p> </li> </ul> </div> `, props:['posts'] }; var Vmain = { // 局部組件 template:` <div class='main'> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts = 'appPosts' /> </div> </div> `, components:{ // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫: Vheader, // 掛載子組件:頭部組件 Vaside, // 掛載子組件:側邊欄組件 Vcontent }, props:['title', 'appPosts'] }; new Vue({ el:"#app", // 注意一個vue裏面只有一個el //第三步.使用子組件 template:"<Vmain v-bind:title='text' :appPosts = 'posts'/>", // title對應屬性名 data: { text:"alex是SB", posts:[ {id:1, title:"組件中傳值1", content:"經過prop傳遞數據1"}, {id:2, title:"組件中傳值2", content:"經過prop傳遞數據22"}, {id:3, title:"組件中傳值3", content:"經過prop傳遞數據333"} ] }, components:{ //第二步.掛載子組件 key表示組件名 value表示組件對象 Vmain:Vmain } }); </script>
顯示效果:
開發 <blog-post>
組件時,它的一些功能可能要求咱們和父級組件進行溝通。例如咱們可能會引入一個可訪問性的功能來放大博文的字號,同時讓頁面的其它部分保持默認的字號。
在其父組件中,咱們能夠經過添加一個 postFontSize
數據屬性來支持這個功能:
new Vue({ el: '#blog-posts-events-demo', data: { posts: [/* ... */], postFontSize: 1 } })
它能夠在模板中用來控制全部博文的字號:
<div id="blog-posts-events-demo"> <div :style="{ fontSize: postFontSize + 'em' }"> <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" ></blog-post> </div> </div>
在每篇文章正文前添加一個按鈕來放大字號。
當點擊這個按鈕時,咱們須要告訴父級組件放大全部博文的文本。幸虧 Vue 實例提供了一個自定義事件的系統來解決這個問題。咱們能夠調用內建的 $emit
方法並傳入事件的名字,來向父級組件觸發一個事件:
Vue.component('blog-post', { props: ['post'], template: ` <div class="blog-post"> <h3>{{ post.title }}</h3> /*<button> Enlarge text </button>*/ <button v-on:click="$emit('enlarge-text')"> Enlarge text </button> <div v-html="post.content"></div> </div> ` })
<script type="text/javascript"> var Vcontent = { // 聲明內容區組件 template:` <div class="content"> <ul> <li v-for="post in posts" :key="post.id"> // 對應id <h3>個人博客標題:{{post.title}}</h3> <p>個人博客內容:{{post.content}}</p> </li> </ul> <button @click="changeSize">改變字體大小</button> </div> `, props:['posts'], methods:{ // 聲明方法 changeSize(){ // 經過$emit()方法傳入事件名字,來觸發自定義的事件 this.$emit('postChangeSize') } } }; var Vmain = { // 局部組件 template:` <div class='main' :style="{fontSize:fontsize+'px'}"> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts = 'appPosts' @postChangeSize="fontsize+=1" /> // 綁定自定義屬性和自定義事件 </div> </div> `, data(){ return { fontsize:14 // 默認字體大小爲14 } }, components:{ // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫: Vheader, // 掛載子組件:頭部組件 Vaside, // 掛載子組件:側邊欄組件 Vcontent }, props:['title', 'appPosts'] }; new Vue({...)}; </script>
經過點擊按鈕能夠不斷修改字體大小,具體驅動流程以下所示:
頁面顯示效果以下所示:
$emit第一個參數是自定義的事件名字,第二個參數就是傳遞的值。
var Vcontent = { // 聲明內容區組件 template:` <div class="content"> <ul> <li v-for="post in posts" :key="post.id"> // 對應id <h3>個人博客標題:{{post.title}}</h3> <p>個人博客內容:{{post.content}}</p> </li> </ul> <button @click="changeSize">改變字體大小</button> </div> `, props:['posts'], methods:{ // 聲明方法 changeSize(){ // 經過$emit()方法來觸發自定義的事件 // 第一個參數是自定義的事件名字;第二個參數就是傳遞的值。
// this指的是vue實例化對象的子類 this.$emit('postChangeSize', 1) } } }; var Vmain = { // 局部組件 template:` <div class='main' :style="{fontSize:fontsize+'px'}"> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts = 'appPosts' @postChangeSize="clickHandler" /> // 綁定自定義屬性和自定義事件 </div> </div> `, methods:{ clickHandler(value){ this.fontsize += this.fontsize+1; } }, data(){ return { fontsize:14 // 默認字體大小爲14 } }, components:{ // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫: Vheader, // 掛載子組件:頭部組件 Vaside, // 掛載子組件:側邊欄組件 Vcontent }, props:['title', 'appPosts'] };
組件傳值是vue中最重要的知識點。
(1)給子組件中的某個按鈕綁定原生事件,能夠調用內建方法this.$emit('自定義事件名','傳遞的數據'),來向父級組件觸發一個自定義的事件。
(2)在父組件中的子組件標籤中要綁定自定義的事件。
全局註冊的組件能夠用在其被註冊以後的任何(經過 new Vue
)新建立的 Vue 根實例,也包括其組件樹中的全部子組件的模板中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
padding:0;
margin:0;
}
#head {
width: 100%;
height: 80px;
background-color: purple;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
// 建立公共組件
// 第一個參數是公共組件的名字;第二個參數options(與局部組件相同)
Vue.component('Vbtn', {
template:`<button>登陸</button>`
});
var Vheader = { // 這裏使用Vheader的緣故是,html5中有header標籤
template:`<div id="header">
<Vbtn></Vbtn>
<Vbtn></Vbtn>
<Vbtn></Vbtn>
</div>`
};
// 局部組件的使用
var App = {
template:`<div>
<Vheader></Vheader>
</div>`,
components: {
Vheader
}
};
new Vue({
el: '#app',
data(){ // 組件中必定是函數
},
template:'<App/>', // 注意必定是閉合標籤
components: {
App // App組件
}
})
</script>
</body>
</html>
頁面顯示效果以下:
全局組件的使用: Vue.component('全局組件的名稱', { 跟new.Vue()實例化對象中的options是同樣的,可是要注意是: 不論是公共組件仍是局部組件,data必須是一個函數,函數必定要有返回值(哪怕是一個空對象{}) })
Vue 實現了一套內容分發的 API,這套 API 基於當前的 Web Components 規範草案,將 <slot>
元素做爲承載分發內容的出口。
<head>代碼省略</head> <body> <div id="app"></div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> // 建立公共組件 // 第一個參數是公共組件的名字;第二個參數options Vue.component('Vbtn', { template:`<button> <slot></slot> </button>` }); var Vheader = { // 這裏使用Vheader的緣故是,html5中有header標籤 template:`<div id="header"> <Vbtn>登陸</Vbtn> <Vbtn>註冊</Vbtn> <Vbtn>提交</Vbtn> </div>` }; """代碼省略""" </script> </body> </html>
若是不使用slot,像上面這麼在模板中添加不一樣的信息是不顯示的。使用vue內置組件slot後顯示效果以下:
<script type="text/javascript"> // 建立公共組件 // 第一個參數是公共組件的名字;第二個參數options Vue.component('Vbtn', { template: `<button class="default" :class="type"> <slot></slot> </button>`, props: ['type'] }); var Vheader = { // 這裏使用Vheader的緣故是,html5中有header標籤 template: `<div id="header"> <Vbtn>登陸</Vbtn> <Vbtn>註冊</Vbtn> <Vbtn>提交</Vbtn> <Vbtn>默認按鈕</Vbtn> <Vbtn type="primary">主要按鈕</Vbtn> <Vbtn type="success">成功按鈕</Vbtn> </div>` }; """代碼省略""" </script>
這裏應用了vue的v-bind:class來給每一個標籤元素添加class。
props:一個 prop 被註冊以後,能夠把數據做爲一個自定義特性傳遞進來。
所以在「<Vbtn type="success">成功按鈕</Vbtn> 」,中給type定義了一個屬性,經過props組件傳值傳遞到公共組件中,由此就能夠對網頁中全部的按鈕進行一個修飾。
Element - 網站快速成型工具:http://element-cn.eleme.io/#/zh-CN
添加css代碼以下所示:
<style> * { padding: 0; margin: 0; } #head { width: 100%; height: 80px; background-color: purple; } button { display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background: #fff; border: 1px solid #dcdfe6; border-top-color: rgb(220, 223, 230); border-right-color: rgb(220, 223, 230); border-bottom-color: rgb(220, 223, 230); border-left-color: rgb(220, 223, 230); border-color: #dcdfe6; color: #606266; text-align: center; box-sizing: border-box; outline: none; margin: 0; transition: .1s; font-weight: 500; padding: 12px 20px; font-size: 14px; border-radius: 4px; } .primary { color: #fff; background-color: #409eff; border-color: #409eff; } .success { color: #fff; background-color: #67c23a; border-color: #67c23a; } </style>