在這一節裏,咱們將會了解到Vue的組件,理解組件是如何工做的,並利用一系列
的例子證實,用組件化的思想開發項目,會給你帶來不同感覺。若是咱們理解了Vue的組件化思想,咱們就能夠利用這個思想構造一個簡化的評論投票系統,一個用戶能夠發佈評論,其餘用戶能夠在任意的評論上面投「同意票」或者投「反對票」。css
若是你是第一次接觸Vue的話,你能夠看看我以前的文章,《從零開始學Vue》,瞭解Vue的基本語法。html
利用組件可以很好的把一個你正在構建的具備複雜接口的應用拆分開來,同時,組件也具備很高的複用性,即便是在你正在開發的是不一樣的項目也能封裝複用。vue
先建立一個簡單的html頁面,並將Vue實例化後掛載在咱們的DOM元素上。git
<!DOCTYPE html> <html> <head> <title>揭開Vue組件的神祕面紗</title> </head> <body> //這中間就是實例掛載點的實例邊界 <div id="vueInstance"></div> //Vue的CDN,以後會省略不寫 <script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script> <script> // 建立一個新的Vue實例,並設置掛載點 var V = new Vue({ el : '#vueInstance' }); </script> </body> </html>
如今咱們已經把在《從零開始學Vue》的基礎都準備好了,而後咱們將建立咱們的第一個簡單的,可複用的組件。在Vue中你,可使用Vue.component()來建立和註冊你的組件,這個構造器有兩個參數:github
組件的名字ajax
包含組件參數的對象數據庫
這個對象有點像Vue()構造器裏的對象,它也有相似於Vue()裏的el屬性和data屬性,可是又有點不同。segmentfault
Vue()構造器的el和data能夠是對象。
Vue.component()構造器的el和data只能是函數。數組
如今來看看第一個組件是如何運做的。我想要註冊一個組件,用p標籤輸出一行個人自我介紹。因此我建立了一個組件,並填入兩個參數:ide
組件的名字:'mine'
包含組件參數的對象:這個對象包含一個屬性'template'
Vue.component('mine',{ template : '<p>My name is Appian.</p>' })
如今你已經有了本身的一個組件了,你能夠在你的應用的任何地方使用它。只要你調用它的惟一標識(就是組件名字),並用普通html標籤的格式來書寫,好比<mine></mine>,組件上註冊的內容就會在你的自定義標籤的地方插入。
<div id="vueInstance"> <mine></mine> //標識註冊的內容會在這裏插入 <mine></mine> <mine></mine> //重複插入註冊內容 </div> <script> Vue.component('mine',{ //這裏就是註冊的內容 template : '<p>My name is Appian.</p>' }); var V = new Vue({ el : '#vueInstance' }); </script>
Vue使用模板Template來代替組件,並使自定義的惟一標識用html標籤插入到DOM結構中去,使得html更加簡潔、整齊和直觀。
如今你可能會想,我寫的組件怎麼可能只有一行p標籤?一行p標籤還有必要組件這麼麻煩嗎?是的,組件是爲了更復雜的封裝複用而生的。因此,若是你只會Vue.component()構造器中的template屬性定義html代碼,利用字符串拼接拼出全部的代碼,這樣只會讓你比用jq更加疲憊不堪。
爲了不上面的這種狀況,因此咱們能夠用template標籤(注意屬性和標籤是不同的)來達到咱們的目的。咱們能夠在頁面的任何地方,定義template標籤,並在template標籤內,寫好咱們的模板。由於template標籤在頁面加載的時候不會渲染出來,只有在咱們須要它的時候,這個標籤內的內容纔會被渲染出來。因此,你能夠把template標籤放在任何地方,並給它一個id,以便在組件註冊的時候可以找到模板。
<div id="vueInstance"> <mine></mine> //標識註冊的內容會在這裏插入 </div> <template id="mineTpl"> <p>My name is Appian.</p> <button>點擊沒有任何事件</button> </template> <script> Vue.component('mine',{ //這裏就是註冊的內容 template : '#mineTpl' }); var V = new Vue({ el : '#vueInstance' }); </script>
咱們如今已經能夠利用這樣的方法建立一個複雜的組件了。這樣咱們可能將複雜的代碼進行功能分區以後組件化,用組件的思想避免代碼一坨一坨的。組件化可以幫你更清晰的組織好你的模塊,使你的組件更加vue化。
每次建立組件實例的時候,這個實例都劃分了本身的組件範圍,這個範圍致使了在這個組件區域內沒法得到其父組件的數據。因此,Vue是如何處理父組件向子組件中傳遞數據的呢?答案是,經過props。
先看一個最簡單,從父組件向子組件中傳遞data的例子。註冊的mine組件是子組件,他但願從父組件那裏獲得‘city’這個數據的信息,因此在mine的構造器裏增長了一個參數props,用來接收父組件傳遞過來的city的值。
Vue.component('mine',{ template : '<p>Appian is from {{ city }}.</p>', props : ['city'] });
上面的例子中,咱們定義了props做爲一個數組,因此props能夠用來接收多個字段,而這些字段就是子組件指望從父組件那裏獲得的。
props不必定要是數組,也能夠是對象。能夠在對象中詳細的定義不少props的限制條件。
Vue.component('mine',{ template : '<p>Appian is from {{ city }}.</p>', props : { city : { type : String,//定義字符串類型 required : true,//該字段是必須的 default : 'China'//設置默認值 } } });
咱們不須要每次都將props的限制條件都寫出來,由於在這個例子中的數據是一個很簡單的字段,上例中只是爲了完整展現props的對象表示方法,因此才展開來寫的。
那父組件那裏又是怎麼指派字段給子組件的呢?
<mine city="FuJian-YongAn"></mine>
這樣直接在mine標籤裏面定義‘city’字段,就是父組件指派字段的方式之一。可是這樣直接指派是很瞎的,咱們須要的是動態變化的city,這個一會咱們會說到的。
先簡單介紹一下咱們接下來要作的事。咱們要僞裝咱們正在搭一個博客,博客須要展現做者的基本信息,此時,咱們可能會須要一些數據對象,多是從數據庫得到的,或者ajax請求到的,總之就是請求到了以後,將這個數據對象定義在父級的data中。並在html的template標籤中準備渲染。
<div id="vueInstance"> <mine></mine> //標識註冊的內容會在這裏插入,以後也要展開來講!!! </div> <template id="mineTpl"> <h1>{{ name }}</h1> <h2>{{ title }}</h2> <h3>{{ city }}</h3> <p>{{ content }}</p> </template> <script> //Vue.component()的構造在下文中展開來講!!! var V = new Vue({ el : '#vueInstance', data : { name : 'Appian', title : 'This is a title', city : 'FuJian-XiaMen', content : 'There are some desc about Appians Blog' } }); </script>
準備好模板渲染以後,固然也要註冊mine的構造器Vue.component()。除了基本的綁定模板id(#mineTpl)以外,還須要指定這個子組件想要的數據的字段名,並把指望獲得的4個字段寫在props中。
Vue.component('mine',{ template : '#mineTpl', props : ['name','title','city','content'] });
這樣咱們就能告訴父級,子組件須要的字段是哪些。接下來父級就能夠指派字段的值給子組件了。前面的city字段是寫死的,如今這裏綁定的字段就是動態綁定的。
<mine :name='name' :title='title' :city='city' :content='content' ></mine>
等號左右兩邊的字段名稱能夠不同。
等號左邊的字段名,是指在子組件的props中聲明的名字。在html寫成肉串式,可是在props中寫成駝峯式。
等號右邊的字段名,是指在父級裏定義的字段的名字。‘:’是‘v-bind’的縮寫
這樣就能把父組件的4個字段綁定到子組件上。如今,只要父組件指派的字段的值一發生改變,子組件的值也會發生相應的改變。
如今就能夠利用前面學到的內容,搭建一個簡易的評論社區系統,樣式什麼的先無論,只講究js的具體實現。
建立一個新的Vue實例
給實例掛載一個div(#vueInstance)
定義數據,而後渲染。
<div id="vueInstance"> <div class="container"> <ul> //這裏即將渲染出評論的投票列表 </ul> </div> </div> <template id="postTpl"> <li> <i class="up">我支持</i> <span>票數: {{ post.votes }}</span> <i class="down">我反對</i> <a>話題: {{ post.title }}</a> </li> </template> <script> //Vue.component()的構造在下文中展開來講!!! var V = new Vue({ el : '#vueInstance', data : { posts: [{ title: '請大大多多爲我投票,我給你們發紅包', votes: 15 },{ title: '投我準沒錯', votes: 53 },{ title: '不要投給我樓上的', votes: 10 }] } }); </script>
如今先構造好數據,有投票的話題和投票人數。而後再構造好模板(template標籤),這個模板值用來渲染單個話題。模板裏有除了渲染話題和投票人數,還有兩個按鈕,用來投同意票或者反對票。以後咱們只須要在html循環模板,而後就能屢次插入模板,渲染成列表。固然也能夠在模板裏渲染好列表再一次插入。咱們先用前一種方法。
無論css的樣式問題,如今就能夠開始註冊Vue.component()構造器了,以便咱們渲染頁面。咱們在註冊的時候要明確,我註冊的子組件須要的props是父級的posts數組中的一個元素對象post。因此咱們應該這樣註冊:
Vue.component('post',{ template : '#postTpl', props : ['post'] });
而後咱們使用自定義的<post>標籤插入在html中去。
<div id="vueInstance"> <div class="container"> <ul> <post v-for="post in posts" :post="post"></post> </ul> </div> </div>
這樣咱們就已經完成了循環輸出posts數組了。由於咱們把數組的元素指派給了子組件,因此子組件就能夠渲染title和vote。接下來要作的就是增長「同意」和「反對」按鈕的邏輯代碼,並咱們須要對投票狀態進行鎖定,就是若是咱們投了某個話題的同意票就不能再投該話題的反對票,反之亦然。
因此讓咱們開始在模板裏面定義點擊事件吧,投同意票的事件叫作「upvote」,投反對票的事件叫作「downvote」。
<template id="postTpl"> <li> <i class="up" @click="upvote">我支持</i> <span>票數: {{ post.votes }}</span> <i class="down" @click="downvote">我反對</i> <a>話題: {{ post.title }}</a> </li> </template>
Vue.component('post',{ template : '#postTpl', props : ['post'], data : function (){ return { //data必須爲function,定義投票狀態 upvoted: false, downvoted: false } }, methods : { upvote : function() { //點擊同意的事件 this.upvoted = !this.upvoted; this.downvoted = false; }, downvote: function() { //點擊反對的事件 this.downvoted = !this.downvoted; this.upvoted = false; } } });
注意,data裏面的兩個布爾值的定義是做爲一個函數的返回值定義的。那是由於咱們想要給每個組件都設置一個是否投票的狀態。
(還記得以前我說過,此次的列表渲染是循環渲染多個模板,每一個模板都只是一個話題的相關信息,而如今在組件中定義的data:upvoted和downvoted,也是專屬於某個模板的。)
這樣咱們若是投了某個話題的同意票,並不會影響剩下話題的投票狀況。
接下來已經完成了點擊事件的狀態控制,那麼點擊「同意」和「反對」會致使話題的票數發生變化。這個時候咱們能夠利用以前的教程中學過的computed屬性進行計算。
組件也有computed屬性哦~
Vue.component('post',{ template : '#postTpl', props : ['post'], data : function (){ //同上,略 }, methods : { //同上,略 }, computed: { //重點部分 votes: function () { if (this.upvoted) { return this.post.votes + 1; } else if (this.downvoted) { return this.post.votes - 1; } else { return this.post.votes; } } } });
到此爲止,應該組件中的邏輯處理差很少完成了,如今要作的就是讓咱們在組件中修改的投票人數,可以在模板中渲染出來。由於咱們如今的votes的值是在子組件中修改的,而一開始渲染的時候,咱們的votes只是一味的接受父級傳過來的值,因此,如今要把修改的值顯示在模板上。
因此模板變成了這樣:
<template id="postTpl"> <li> <i class="up" @click="upvote">我支持</i> <span>票數: {{ votes }}</span> <i class="down" @click="downvote">我反對</i> <a>話題: {{ post.title }}</a> </li> </template>
如今咱們的投票系統已經基本完成了。咱們可能會但願咱們的投票系統好看一點,直觀一點。因此咱們能夠在按鈕上綁定一些樣式。好比當用戶已經投了某個話題的同意票或者反對票,就讓這個按鈕變成橙色。
.disabled { color : orange; }
Vue是利用v-bind:class來進行樣式綁定的,能夠簡寫成一個‘:’。其綁定的內容是一個對象,對象裏面是class的名字和class對應的狀態。
瞭解更多樣式綁定的信息點這裏
<template id="postTpl"> <li> <i class="up" @click="upvote" :class="{disabled: upvoted}">我支持</i> <span>票數: {{ votes }}</span> <i class="down" @click="downvote" :class="{disabled: downvoted}">我反對</i> <a>話題: {{ post.title }}</a> </li> </template>
若是咱們點擊了某個話題的同意按鈕,則它的upvoted就會變成true,則disabled的樣式就綁定到同意按鈕上去。若是點了該話題的反對按鈕,則它的upvoted就會變成false,則disabled就不會綁定到同意按鈕上。以上就是模板最終的樣子。
咱們已經利用了咱們對Vue的基本語法還有一些組件的基本操做,創建起了一個基本的話題投票系統。在教程的最後一部分,咱們將看看,咱們應該如何將這個投票系統組件進行復用。
複用的關鍵在於組件的命名,讓你的命名可以複用。至少你在構建你的組件的時候,你要問本身,「是否其餘地方也能用到這個組件?」
好比,在上面的例子中,posts的意思是,這個數據是從ajax的post請求過來的數據,爲了便於理解,才取名爲posts,爲了讓本身的組件名字一看就知道關聯,因此把模板的id定義爲#postTpl,tpl是template的簡寫,自定義標籤的命名也是post。總之,就是這樣的細節,不只方便本身閱讀,也方便其餘人閱讀你的代碼。
如今咱們的評論系統須要增長一個功能,就是增長一個發佈評論的功能。就是增長了一個發佈評論的區域(#commentBox)。
<div id="vueInstance"> <div class="container"> <ul> <post v-for="post in posts" :post="post"></post> </ul> <div id="commentBox"> 請輸入評論內容並提交: <input type="text" v-model="comment" @keyup.enter="postComment"> <button @click="postComment">提交評論</button> </div> </div> </div> //模板渲染不變 <script> //Vue.component()的註冊不變。 var V = new Vue({ el : '#vueInstance', data : { posts: [{ title: '請大大多多爲我投票,我給你們發紅包', votes: 15 },{ title: '投我準沒錯', votes: 53 },{ title: '不要投給我樓上的', votes: 10 }], comment: '' }, methods: { postComment: function() { this.posts.push({ title: this.comment, votes: 0 }) this.comment = ''; } } }); </script>
輸入框用v-model綁定了comment字段,爲了不管用戶輸入什麼,在提交的時候都能得到他輸入的值。當用戶按回車或者點擊提交按鈕的時候都會觸發postComment方法。這裏的事件綁定一個是用的回車事件 @keyup.enter,還有一個點擊事件@click。postComment方法就是把話題和投票爲0的對象push進posts數組中去,Vue會將新的模板自動渲染出來。
這樣一個可複用的組件就構造完成了,組件化會節省開發者的不少時間。組件是否複用,也要結合開發的實際需求而定。
到此爲止,你就已經可以掌握了Vue的組件的基本使用,組件經過props向下傳遞數據,經過使用<template>標籤來構造模板。咱們在上文中利用構建了一個評論發佈投票系統來講明瞭組件的用法,而且簡單介紹瞭如何複用。
利用 props,子組件能夠定義須要父級傳遞的字段
利用 'v-bind:' 或 ':' 在自定義標籤的地方綁定父級指派的字段
組件的 data 和 el 必須定義爲function
不要忘記,仍是須要將Vue實例化,才能使用組件。
github地址
https://github.com/AppianZ/Close2Vue
推薦一個Vue交流羣:364912432