Vue.js是一套構建用戶界面的漸進式框架(官方說明)。通俗點來講,Vue.js是一個輕量級的,易上手易使用的,便捷,靈活性強的前端MVVM框架。簡潔的API,良好健全的中文文檔,使開發者可以較容易的上手Vue框架。javascript
本系列文章將結合我的在使用Vue中的一些經(cai)驗(keng)和一些案例,對Vue框架掌握的部分知識進行輸出,同時也鞏固對Vue框架的理解。css
認識組件
組件是 Vue 強大的功能之一。Vue組件具備封裝可複用的特色,可以讓你在複雜的應用中拆分紅獨立模塊使用。注意,全部的 Vue 組件同時也都是 Vue 的實例,可接受相同的選項對象。html
咱們能夠經過全局註冊和局部註冊的方式來註冊一個 Vue 組件,兩種方式的區別在於,全局註冊的組件可以在任何地方使用,其實就是全部的 Vue 實例化的時候都會去渲染這個全局組件;而局部組件只是註冊在某一個 Vue 實例化對象上,只能在這個 Vue 實例化的時候會渲染,其餘地方使用會被當成普通的Html標籤渲染。咱們就先來了解下全局組件的註冊。
Vue 組件全局註冊時經過 Vue.component(tagName, options)
方式註冊。 看一個簡單的示例。前端
<div id="app" class="demo"> <!-- Vue組件 --> <simple-component></simple-component> </div> <script> Vue.component("simple-component", { template: "<span>我是一個最簡單的Vue組件示例</span>" }) new Vue({ el: "#app" }) </script>
Vue.component 方法中傳入兩個參數,一個參數是組件的自定義標籤名,另外一個參數是一個對象,裏面的template屬性的值就是組件的模板。vue
可能你會想,組件的內容太簡單了吧,只有一個標籤,要是內容複雜點的組件,難道也要像之前同樣用字符串把內容都拼接起來嗎?感受太恐怖了,就算是使用了es6的字符串語法,寫下去也是一大推,很不優雅感受。嗯,是的,針對這個問題,在 Vue 中給出了良好的解決方案,可使用 <script type="x-template">
標籤來處理複雜的組件模板。java
<div id="app2" class="demo"> <vut-button></vut-button> </div> <script type="x-template" id="vComponent"> <div class="vut-button"> <span>我是Button組件</span> </div> </script> <script> Vue.component("vut-button", { template: "#vComponent" }) new Vue({ el: "#app2" }) </script>
固然,爲了可以讓代碼看起來更加清晰明瞭點,你可使用 template
標籤來包裹組件模板,template
標籤在瀏覽器渲染過程當中不會被渲染出來。git
<div id="app-test" class="demo"> <vut-button></vut-button> </div> <template id="vComponent"> <div class="vut-button"> <span>我是Button組件</span> </div> </template> <script> Vue.component("vut-button", { template: "#vComponent" }) new Vue({ el: "#app-test" }) </script>
好了,那麼局部組件應該怎麼註冊呢?你能夠經過在Vue實例選項components
註冊僅在其做用域中可用的局部組件。es6
<div id="app-local" class="demo"> <!-- Vue組件 --> <simple-component></simple-component> </div> <script> new Vue({ el: "#app-local", components: { "simple-component": { template: "<span>我是一個最簡單的局部Vue組件示例</span>" } } }) </script>
Vue實例選項components
包含了一個屬性,鍵是組件的名稱,值是一個對象,包含了組件的模板等屬性。github
每一個Vue組件實例都有獨立範圍的做用域的,這意味着子組件的模板中沒法獲取到父組件的數據,那麼Vue能夠經過使用props參數來實現父組件向子組件傳遞數據。web
<div id="app" class="demo"> <simple-component link="https://github.com/vuejs/vue"></simple-component> </div> <script> Vue.component("simple-component", { template: "<span>Vue的github地址是:{{ link }}</span>", props: ["link"] }) new Vue({ el: "#app" }) </script>
能夠看到,咱們定義了一個props數組接收來自父組件傳遞的數據,由於父組件傳遞的數據多是多個。而事實上,props不必定是數組,也能夠是對象,能夠詳細的指定父組件傳遞的數據規則,包括默認值,數據類型等。
props: { link: { type: String, //數據類型 defalut: "https://www.baidu.com/" //默認值 } }
那麼父組件如何動態的傳遞數據給子組件呢?還記得v-bind指令的做用嗎,其做用是用於動態綁定html屬性或者是組件的props值
,因此應該使用v-bind指令來動態傳遞數據。
<template id="userComponent"> <div> <p>用戶名:{{ userName }}</p> <p>性別:{{ sex }}</p> <p>年齡:{{ age }}</p> </div> </template> <script type="text/javascript"> Vue.component("user-component", { template: "#userComponent", props: ["userName", "sex", "age"] }) </script> <div id="app2" class="demo"> <div> <input type="text" v-model="userName" placeholder="請輸入用戶名"> <input type="text" v-model="sex" placeholder="請輸入性別"> <input type="text" v-model="age" placeholder="請輸年齡"> </div> <user-component :user-name="userName" :sex="sex" :age="age" > </user-component> </div> <script type="text/javascript"> new Vue({ el: "#app2", data: { userName: "", sex: "", age: "" } }) </script>
咱們知道,父組件使用 prop 傳遞數據給子組件。但子組件怎麼跟父組件通訊呢?這個時候 Vue 的自定義事件系統就派得上用場了。
假設咱們在寫一個評論系統,評論部分是Vue組件,評論提交以後咱們要將評論的內容展現出來。
先來寫出評論組件吧
<template id="comment-component"> <div class="i-comment-area"> <textarea rows="5" class="i-textarea" placeholder="請輸入內容" v-model="commentValue"></textarea> <div class="i-comment-submit" @click="handleSubmit"> <span>提交</span> </div> </div> </template>
評論組件模板包含了一個輸入框和一個提交評論的按鈕,就這麼簡單,而後,就全局註冊這個組件
Vue.component("i-comment", { template: "#comment-component", data: function(){ return { commentValue: "" } }, methods: { handleSubmit: function(){ if(this.commentValue.length < 1){ alert("評論不能爲空"); return; } this.$emit("content", this.commentValue); this.commentValue = ""; } } })
可能你會發現,組件裏的data實例選項跟以前的寫法不同,是的,這個在寫組件的時候要注意的地方,Vue規定了組件中的data選項必須是函數
。而後給提交按鈕綁定了一個點擊事件handleSubmit
,當你填寫了評論內容,並點擊提交評論的時候,組件會經過 $emit(eventName)
觸發事件,並帶有一個參數,就是把評論的內容傳遞給父組件。
既然子組件是經過 $emit(eventName)
來和父組件通訊,那麼父組件如何接收子組件傳遞過來的數據呢,答案是,使用 $on(eventName)
監聽事件。
<div id="simple-comment" class="demo"> <i-comment v-on:content="commentData"></i-comment> <label class="title">評論列表</label> <ul class="comment-list"> <li v-for="(item,index) in commentList"> <span>{{ item.time }}</span> <span>{{ item.content }}</span> </li> </ul> </div>
在父組件中,監聽子組件中定義的事件名,並調用一個方法 commentData
。commentData方法用來獲取子組件傳遞給父組件的參數,這樣就是一個子組件向父組件通訊的過程。 能夠查看完整的例子 。
接下來,經過實際動手來實現一個 Switch UI 組件。首先思考下Switch組件須要有哪些基本的API。
- 考慮到使用場景,須要制定不一樣尺寸的Switch組件,因此須要
size
API。- 考慮到會出現禁止使用的場景,須要禁止和啓用組件的功能,因此須要
disabled
API。- 考慮到須要自定義開啓和關閉時的背景顏色,因此須要
on-color
和off-color
API來自定義背景色。- 同理,可能須要自定義開啓和關閉時顯示的文字,因此須要
on-text
和off-text
API來自定義顯示的文字。- 可能還會須要經過事件監聽來獲取當前的狀態,並根據狀態作一些操做,因此須要一個事件來監聽狀態的變化,因此須要
on-change
API。
那麼基本的API都列出來了,如今就能夠開始一步步實現這些功能了。首先寫出組件模板的基本框架。
<span :class="wrapClass"> <span :class="switchClass" @click="handleChangeFn" ref="switch"> <input type="hidden" :value="currentValue"> </span> </span>
而後得註冊這個組件吧。
var prefixClass = "vut-switch"; Vue.component("vut-switch",{ template: "#switch-component", props: { value: { type: Boolean, default: false } }, data: function(){ return { currentValue: this.value //當前狀態 } }, computed: { wrapClass: function(){ return prefixClass + "-wrap"; }, switchClass: function(){ return [ prefixClass, { [prefixClass + "-checked"]: this.currentValue } ]; } } })
基本上架子就搭建好了。 而後就開始實現那些列出來的API。先來看如何實現size尺寸。
size尺寸的值確定是經過父組件傳遞過來的,因此就先在子組件中的props選項中定義好size對象。
props: { value: { type: Boolean, default: false }, size: String //尺寸 }
而後咱們的思路是經過不一樣的樣式來控制渲染出來的Switch組件。咱們根據傳入的不一樣尺寸的值來添加不一樣的Class值,制定不一樣的樣式,因此switchClass計算屬性中可這麼寫:
switchClass: function(){ return [ prefixClass, { [prefixClass + "-checked"]: this.currentValue, [prefixClass +"-"+ this.size]: this.size } ]; }
而後就是添加對應的樣式。
/*小尺寸*/ .vut-switch-small{ width: 40px; height: 20px; } .vut-switch-small:after{ width: 16px; height: 16px; } .vut-switch-small.vut-switch-checked:after{ left: 22px; } /*大尺寸*/ .vut-switch-large{ width: 60px; } .vut-switch-large.vut-switch-checked:after{ left: 38px; }
最後咱們就在Vue實例初始化模板中使用Switch組件。
<vut-switch size="small"></vut-switch> <vut-switch size="large"></vut-switch>
這樣咱們就能夠控制顯示Switch組件的尺寸了,效果以下:
而後來看看如何實現自定義背景色的。一樣也是先在子組件的props選項中定義好傳遞過來的數據。
props: { value: { type: Boolean, default: false }, size: String, //尺寸 onColor: String, //開啓時的自定義背景色 ofColor: String //關閉時的自定義背景色 }
而後咱們經過當前的狀態來控制顯示不一樣的背景色,也就是要關注 currentValue
值。先來寫一個設置背景色的函數,根據currentValue值的變化來設置背景色。
setBackgroundColor: function(){ let customColor = this.currentValue ? this.onColor : this.offColor; this.$refs.switch.style.backgroundColor = customColor; }
而後監聽currentValue值的變化來調用這個函數。
watch: { currentValue: function(){ this.setBackgroundColor(); } }
最後咱們就在Vue實例初始化模板中使用Switch組件。
<vut-switch on-color="#13ce66" off-color="#ff4949"></vut-switch>
效果以下:
完整的例子請查看 switch組件 。
本着學習和總結的態度寫的文章,文中有任何錯誤和問題,能夠在github上指出 issues 。文中的案例都放置在github上,地址:https://github.com/webproblem/IntoVue。