認識Vue元件

惆悵客發表於2017-12-15

前言

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-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元件的尺寸了,效果如下:

認識Vue元件

然後來看看如何實現自定義背景色的。同樣也是先在子元件的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>
複製程式碼

效果如下:

認識Vue元件

完整的例子請檢視 switch元件

後記

本著學習和總結的態度寫的文章,文中有任何錯誤和問題,可以在github上指出 issues 。文中的案例都放置在github上,地址:github.com/webproblem/…

相關文章