認識Vue組件

前言

Vue.js是一套構建用戶界面的漸進式框架(官方說明)。通俗點來講,Vue.js是一個輕量級的,易上手易使用的,便捷,靈活性強的前端MVVM框架。簡潔的API,良好健全的中文文檔,使開發者可以較容易的上手Vue框架。javascript

本系列文章將結合我的在使用Vue中的一些經(cai)驗(keng)和一些案例,對Vue框架掌握的部分知識進行輸出,同時也鞏固對Vue框架的理解。css

認識組件

組件是 Vue 強大的功能之一。Vue組件具備封裝可複用的特色,可以讓你在複雜的應用中拆分紅獨立模塊使用。注意,全部的 Vue 組件同時也都是 Vue 的實例,可接受相同的選項對象。html

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屬性的值就是組件的模板。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

使用 Prop 傳遞數據

每一個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 UI 組件。首先思考下Switch組件須要有哪些基本的API。

  • 考慮到使用場景,須要制定不一樣尺寸的Switch組件,因此須要 size API。
  • 考慮到會出現禁止使用的場景,須要禁止和啓用組件的功能,因此須要 disabled API。
  • 考慮到須要自定義開啓和關閉時的背景顏色,因此須要 on-coloroff-color API來自定義背景色。
  • 同理,可能須要自定義開啓和關閉時顯示的文字,因此須要 on-textoff-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

相關文章
相關標籤/搜索