Vue.js 2.x:組件的定義和註冊(詳細的圖文教程)

本文最初發表於博客園,並在GitHub上持續更新前端的系列文章。歡迎在GitHub上關注我,一塊兒入門和進階前端。javascript

如下是正文。html

前言

什麼是組件

組件: 組件的出現,就是爲了拆分Vue實例的代碼量的,可以讓咱們以不一樣的組件,來劃分不一樣的功能模塊,未來咱們須要什麼樣的功能,就能夠去調用對應的組件便可。前端

模塊化和組件化的區別

  • 模塊化:是從代碼邏輯的角度進行劃分的;方便代碼分層開發,保證每一個功能模塊的職能單一vue

  • 組件化:是從UI界面的角度進行劃分的;前端的組件化,方便UI組件的重用java

全局組件的定義和註冊

組件Component是 Vue.js 最強大的功能之一。組件能夠擴展 HTML 元素,封裝可重用的代碼。git

全局組件的定義和註冊有三種方式,咱們接下來說一講。github

寫法一

寫法一:使用Vue.extend方法定義組件,使用 Vue.component方法註冊組件。微信

代碼舉例:app

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 若是要使用組件,直接把組件的名稱,以 HTML 標籤的形式,引入到頁面中,便可 -->
        <account> </account>
    </div>

    <script>
        //第一步:使用 Vue.extend 定義組件
        var myAccount = Vue.extend({
            template: '<div><h2>登陸頁面</h2> <h3>註冊頁面</h3></div>' // 經過 template 屬性,指定了組件要展現的HTML結構。template 是 Vue 中的關鍵字,不能改。
        });
        //第二步:使用 Vue.component 註冊組件
        // Vue.component('組件的名稱', 建立出來的組件模板對象)
        Vue.component('account', myAccount); //第一個參數是組件的名稱(標籤名),第二個參數是模板對象

        new Vue({
            el: '#app'
        });
    </script>
</body>

</html>

上方代碼中,在註冊組件時,第一個參數是標籤名,第二個參數是組件的定義。模塊化

運行結果以下:

代碼截圖以下:

上圖中,注意兩點:

注意1、紅框部分,要保證兩者的名字是一致的。若是在註冊時,組件的名稱是駝峯命名,好比:

Vue.component('myComponent', myAccount); //第一個參數是組件的名稱(標籤名),第二個參數是模板對象

那麼,在標籤中使用組件時,須要把大寫的駝峯改成小寫的字母,同時兩個單詞之間使用-進行鏈接:

<my-component> </my-component>

Vue.component('my')

注意2、綠框部分,必定要用一個大的根元素(例如<div>)包裹起來。若是我寫成下面這樣,就沒有預期的效果:

template: '<h2>登陸頁面</h2> <h3>註冊頁面</h3>'

結果以下:(並不是預期的效果)

寫法二

寫法二:Vue.component方法定義、註冊組件(一步到位)。

代碼以下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <account> </account>
    </div>

    <script>

        //定義、註冊組件:第一個參數是組件的名稱(標籤名),第二個參數是組件的定義
        Vue.component('account', {
            template: '<div><h2>登陸頁面</h2> <h3>註冊頁面</h3></div>'   // template 是 Vue 中的關鍵字,不能改。
        });

        new Vue({
            el: '#app'
        });
    </script>
</body>

</html>

代碼截圖以下:

上圖中,一樣注意兩點:

一、紅框部分,要保證兩者的名字是一致的。

二、綠框部分,必定要用一個大的根元素(例如<div>)包裹起來。若是我寫成下面這樣,就沒有預期的效果:

template: '<h2>登陸頁面</h2> <h3>註冊頁面</h3>'

結果以下:(並不是預期的效果)

寫法三

上面的寫法1、寫法二並非很智能,由於在定義模板的時候,沒有智能提示和高亮,容易出錯。咱們不妨來看看寫法三。

寫法三:將組件內容定義到template標籤中去。

代碼以下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <!-- 定義模板 -->
    <template id="myAccount">
        <div>
            <h2>登陸頁面</h2>
            <h3>註冊頁面</h3>
        </div>
    </template>

    <div id="app">
        <!-- 使用組件 -->
        <account> </account>
    </div>

    <script>

        //定義、註冊組件
        Vue.component('account', {
            template: '#myAccount'    // template 是 Vue 中的關鍵字,不能改。
        });

        new Vue({
            el: '#app'
        });
    </script>
</body>

</html>

代碼截圖以下:

寫法三其實和方法二差很少,無非是把綠框部分的內容,單獨放在了<template>標籤中而已,這樣有利於 html 標籤的書寫。

使用components定義私有組件

咱們在上一段中定義的是全局組件,這樣作的時候,多個Vue實例均可以使用這個組件。

咱們還能夠在一個Vue實例的內部定義私有組件,這樣作的時候,只有當前這個Vue實例纔可使用這個組件。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>

    <div id="app">
        <!-- 使用Vue實例內部的私有組件 -->
        <my-login></my-login>
    </div>

    <script>

        new Vue({
            el: '#app',
            data: {},
            components: { // 定義、註冊Vue實例內部的私有組件
                myLogin: {
                    template: '<h3>這是私有的login組件</h3>'
                }
            }


        });
    </script>
</body>

</html>

運行效果:

固然,咱們還能夠把模板的定義存放在<template>標籤中,這樣的話,模板裏的html標籤就能夠出現智能提示和高亮,避免出錯。以下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>

    <!-- 定義模板 -->
    <template id="loginTmp">
        <h3>這是私有的login組件</h3>
    </template>

    <div id="app">
        <!-- 調用Vue實例內部的私有組件 -->
        <my-login></my-login>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {},
            components: { // 定義、註冊Vue實例內部的私有組件
                myLogin: {
                    template: '#loginTmp'
                }
            }
        });
    </script>
</body>

</html>

運行效果不變。

爲組件添加 data 和 methods

既然組件是一個頁面,那麼,頁面中可能會有一些功能要動態展現。所以,咱們有必要爲組件添加 data 和 methods。

代碼舉例以下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <!-- 定義組件的模板 -->
    <template id="myAccount">
        <div>
            <!-- 在組件的模板中,調用本組件中的data -->
            {{myData}}
            <a href="#" v-on:click="login">登陸1</a>
            <h2>登陸頁面</h2>
            <h3>註冊頁面</h3>

        </div>
    </template>

    <div id="app">
        <!-- 第一次調用組件 -->
        <account> </account>
        <!-- 第二次調用組件 -->
        <account> </account>
    </div>

    <script>

        //定義、註冊組件
        Vue.component('account', {
            template: '#myAccount',
            //組件中的 data
            //【注意】組件中的data,再也不是對象,而是一個方法(不然報錯);並且這個方法內部,還必須返回一個對象才行
            // 組件中 的data 數據,使用方式,和實例中的 data 使用方式徹底同樣!!!
            data: function () {
                return {
                    myData: 'smyhvae'
                }
            },
            //組件中的 method
            methods: {
                login: function () {
                    alert('login操做');
                }
            }
        });

        new Vue({
            el: '#app'
        });
    </script>
</body>

</html>

上方代碼所示,咱們在account組件中添加的data 和 methods,其做用域只限於account組件裏,保證獨立性。

注意,在爲組件添加數據時,data再也不是對象了,而是function,並且要經過 return的形式進行返回;不然,頁面上是沒法看到效果的。經過 function返回對象的形式來定義data,做用是:

  • 上方代碼中,組件<account>被調用了兩次(不像根組件那樣只能調用一次),可是每一個組件裏的數據 myData是各自獨立的,不產生衝突。

  • 換而言之,經過函數返回對象的目的,是爲了讓每一個組件都有本身獨立的數據存儲,而不該該共享一套數據。

爲何組件的data必須是一個function

咱們先來看下面這樣的例子:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 第一次調用組件 -->
        <counter></counter>
        <hr>

        <!-- 第二次調用組件 -->
        <counter></counter>
    </div>

    <!-- 定義模板 -->
    <template id="tmpl">
        <div>
            <input type="button" value="讓count加1" @click="increment">
            <h3>{{count}}</h3>
        </div>
    </template>

    <script>
        var dataObj = { count: 0 }

        // 這是一個計數器的組件, 身上有個按鈕,每當點擊按鈕,讓 data 中的 count 值 +1
        Vue.component('counter', {
            template: '#tmpl',
            data: function () {
                return dataObj //當咱們return全局的dataObj的時候,子組件們會共享這個dataObj
            },
            methods: {
                increment() {
                    this.count++
                }
            }
        })

        // 建立 Vue 實例,獲得 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {}
        });
    </script>
</body>

</html>

運行效果以下:

上面的例子中,將組件<counter>調用了兩次,因爲dataObj全局對象,致使兩個組件實例均可以共享這個dataObj數據。因而,咱們點擊任何一個組件實例的按鈕,均可以讓count數據加1。

如今問題來了,若是咱們想讓組件<counter>的兩個實例去單獨操做count數據,應該怎麼作呢?咱們應該修改 data中 return出去的內容:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <counter></counter>
        <hr>
        <counter></counter>
        <hr>
        <counter></counter>
    </div>

    <template id="tmpl">
        <div>
            <input type="button" value="讓count加1" @click="increment">
            <h3>{{count}}</h3>
        </div>
    </template>

    <script>
        var dataObj = { count: 0 }

        // 這是一個計數器的組件, 身上有個按鈕,每當點擊按鈕,讓 data 中的 count 值 +1
        Vue.component('counter', {
            template: '#tmpl',
            data: function () {
                // return dataObj //當咱們return全局的dataObj的時候,這個dataObj是共享的
                return { count: 0 } // 【重要】return一個**新開闢**的對象數據
            },
            methods: {
                increment() {
                    this.count++
                }
            }
        })

        // 建立 Vue 實例,獲得 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {}
        });
    </script>
</body>

</html>

運行效果:

如上圖所示,每當咱們建立一個新的組件實例時,就會調用data函數,data函數裏會return一個新開闢的對象數據。這樣作,就能夠保證每一個組件實例有獨立的數據存儲

組件的切換

使用v-if和v-else結合flag進行切換

代碼舉例:(登陸組件/註冊組件,二選一)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 舒適提示:`.prevent`能夠阻止超連接的默認事件 -->
        <a href="" @click.prevent="flag=true">登陸</a>
        <a href="" @click.prevent="flag=false">註冊</a>

        <!-- 登陸組件/註冊組件,同時只顯示一個 -->
        <login v-if="flag"></login>
        <register v-else="flag"></register>

    </div>

    <script>
        Vue.component('login', {
            template: '<h3>登陸組件</h3>'
        })

        Vue.component('register', {
            template: '<h3>註冊組件</h3>'
        })

        // 建立 Vue 實例,獲得 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                flag: false
            },
            methods: {}
        });
    </script>
</body>

</html>

運行效果以下:

使用Vue提供的<component>標籤實現組件切換

上面的例子中,咱們是經過flag的值來進行組件的切換。可是,flag的值只可能有兩種狀況,也就是說,v-if和v-else只能進行兩個組件之間的切換。

那如何實現三個甚至三個以上的組件切換呢?這裏,咱們能夠用到Vue提供的<component>標籤。

咱們先來看一下<component>標籤的用法。

基於上面的代碼,若是我想讓login組件顯示出來,藉助<component>標籤能夠這樣作:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="Vue2.5.16.js"></script>
</head>

<body>
    <div id="app">

        <!-- Vue提供了 component ,來展現對應名稱的組件 -->
        <!-- 【重要】component 是一個佔位符, `:is` 屬性,能夠用來指定要展現的組件名稱。這裏,咱們讓 login 組件顯示出來 -->
        <component :is="'login'"></component>

    </div>

    <script>
        // 組件名稱是 字符串
        Vue.component('login', {
            template: '<h3>登陸組件</h3>'
        })

        Vue.component('register', {
            template: '<h3>註冊組件</h3>'
        })

        // 建立 Vue 實例,獲得 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                comName: 'login' // 當前 component 中的 :is 綁定的組件的名稱
            },
            methods: {}
        });
    </script>
</body>

</html>

上方代碼中,提取關鍵代碼以下:

<component :is="'login'"></component>

若是我想讓register組件顯示出來,藉助<component>標籤能夠這樣作:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="Vue2.5.16.js"></script>
</head>

<body>
    <div id="app">

        <!-- Vue提供了 component ,來展現對應名稱的組件 -->
        <!-- 【重要】component 是一個佔位符, `:is` 屬性,能夠用來指定要展現的組件名稱 -->
        <component :is="'register'"></component>

    </div>

    <script>
        // 組件名稱是 字符串
        Vue.component('login', {
            template: '<h3>登陸組件</h3>'
        })

        Vue.component('register', {
            template: '<h3>註冊組件</h3>'
        })

        // 建立 Vue 實例,獲得 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                comName: 'login' // 當前 component 中的 :is 綁定的組件的名稱
            },
            methods: {}
        });
    </script>
</body>

</html>

上方代碼中,提取關鍵代碼以下:

<component :is="'register'"></component>

所以,若是要實現組件之間的切換,咱們能夠給<component>標籤裏的is屬性值設置爲變量便可,來看看代碼實現。

實現組件切換的完整代碼:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 點擊按鈕後,設置變量`comName`爲不一樣的值,表明着後面的component裏顯示不一樣的組件 -->
        <a href="" @click.prevent="comName='login'">登陸</a>
        <a href="" @click.prevent="comName='register'">註冊</a>

        <!-- Vue提供了 component ,來展現對應名稱的組件 -->
        <!-- component 是一個佔位符, :is 屬性,能夠用來指定要展現的組件的名稱 -->
        <!-- 此處的`comName`是變量,變量值爲組件名稱 -->
        <component :is="comName"></component>

    </div>

    <script>
        // 組件名稱是 字符串
        Vue.component('login', {
            template: '<h3>登陸組件</h3>'
        })

        Vue.component('register', {
            template: '<h3>註冊組件</h3>'
        })

        // 建立 Vue 實例,獲得 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                comName: 'login' // 當前 component 中的 :is 綁定的組件的名稱
            },
            methods: {}
        });
    </script>
</body>

</html>

效果:

個人公衆號

想學習代碼以外的軟技能?不妨關注個人微信公衆號:生命團隊(id:vitateam)。

掃一掃,你將發現另外一個全新的世界,而這將是一場美麗的意外:

相關文章
相關標籤/搜索