前言
Vue.js是一套構建使用者介面的漸進式框架(官方說明)。通俗點來說,Vue.js是一個輕量級的,易上手易使用的,便捷,靈活性強的前端MVVM框架。簡潔的API,良好健全的中文文件,使開發者能夠較容易的上手Vue框架。
本系列文章將結合個人在使用Vue中的一些經(cai)驗(keng)和一些案例,對Vue框架掌握的部分知識進行輸出,同時也鞏固對Vue框架的理解。
認識元件
元件是 Vue 強大的功能之一。Vue元件具有封裝可複用的特點,能夠讓你在複雜的應用中拆分成獨立模組使用。注意,所有的 Vue 元件同時也都是 Vue 的例項,可接受相同的選項物件。
Vue元件的註冊
我們可以通過全域性註冊和區域性註冊的方式來註冊一個 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屬性的值就是元件的模板。
可能你會想,元件的內容太簡單了吧,只有一個標籤,要是內容複雜點的元件,難道也要像以前一樣用字串把內容都拼接起來嗎?感覺太恐怖了,就算是使用了es6的字串語法,寫下去也是一大推,很不優雅感覺。嗯,是的,針對這個問題,在 Vue 中給出了良好的解決方案,可以使用 <script type="x-template">
標籤來處理複雜的元件模板。
<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
標籤在瀏覽器渲染過程中不會被渲染出來。
<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
註冊僅在其作用域中可用的區域性元件。
<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
包含了一個屬性,鍵是元件的名稱,值是一個物件,包含了元件的模板等屬性。
使用 Prop 傳遞資料
每個Vue元件例項都有獨立範圍的作用域的,這意味著子元件的模板中無法獲取到父元件的資料,那麼Vue可以通過使用props引數來實現父元件向子元件傳遞資料。
<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 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上,地址:github.com/webproblem/…。