vue——組件

1、組件概念

  vue的核心基礎就是組件的使用,玩好了組件才能將前面學的基礎更好的運用起來。組件的使用更使咱們的項目解耦合。更加符合vue的設計思想MVVM。javascript

// 定義一個名爲 button-counter 的新組件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

一、組件是可複用的Vue實例

  組件是可複用的 Vue 實例,且帶有一個名字:在這個例子中是 <button-counter>。咱們能夠在一個經過 new Vue 建立的 Vue 根實例中,把這個組件做爲自定義元素來使用:css

<div id="components-demo">
  <button-counter></button-counter>
</div>

new Vue({ el: '#components-demo' })

  由於組件是可複用的 Vue 實例,因此它們與 new Vue 接收相同的選項,例如 datacomputedwatchmethods 以及生命週期鉤子等。僅有的例外是像 el 這樣根實例特有的選項html

二、組件可屢次複用

  能夠將組件進行任意次數的複用:vue

<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

  

  點擊按鈕時,每一個組件都會各自獨立維護它的count。由於你每用一次組件,都會有它的新實例被建立。html5

三、組件中data必須是一個函數

  定義這個 <button-counter> 組件時,你可能會發現它的 data 並非像這樣直接提供一個對象:java

data: {
  count: 0
} 

  取而代之的是,一個組件的 data 選項必須是一個函數,所以每一個實例能夠維護一份被返回對象的獨立的拷貝:node

data: function () {
  return {
    count: 0
  }
}

若是 Vue 沒有這條規則,點擊一個按鈕就可能會影響到其它全部實例。app

2、組件的組織

  一般一個應用會以一棵嵌套的組件樹的形式來組織:ide

  

  例如,你可能會有頁頭、側邊欄、內容區等組件,每一個組件又包含了其它的像導航連接、博文之類的組件。函數

  

  爲了能在模板中使用,這些組件必須先註冊以便 Vue 可以識別。這裏有兩種組件的註冊類型:全局註冊局部註冊

一、vue中全局組件使用

  經過 Vue.component 全局註冊:

Vue.component('my-component-name', {
  // ... options ...
})

  全局註冊的組件能夠用在其被註冊以後的任何 (經過 new Vue) 新建立的 Vue 根實例,也包括其組件樹中的全部子組件的模板中。

二、vue中局部組件的使用

(1)局部組件簡單示例

<body>
    <div id="app"></div>
    <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
        // 聲明頭部組件
        var Vheader = {
            template: `
                <header class="head">
                    我是頭部
                </header>
            `
        };

        // 1.聲明入口組件
        /*
            1.頭部組件
            2.側邊欄
            3.內容組件
            4.腳本組件
         */
        var Vmain = {
            template: `
                <div class="main">
                    我是入口
                    <Vheader></Vheader>
                </div>
            `,
            components:{
                // 掛載子組件
                Vheader,   // 等價於Vheader:Vheader
            }
        };

        new Vue({
            el: '#app',
            // 3.使用子組件
            template: `<Vmain/>`,   // 單閉合
            data: {

            },
            components: {
                // 2.聲明變量,掛載子組件
                Vmain: Vmain
            }
        });
    </script>
</body>

  顯示效果以下所示:

  

(2)局部組件複雜示例

  注意:先聲明子組件、再掛載子組件、最後使用子組件。

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        * {
            padding: 0;
            margin: 0;
        }

        .main {
            width: 100%;
        }

        body {
            color: #fff;
        }

        .head {
            width: 100%;
            height: 70px;
            background-color: purple;
            text-align: center;
            font-size: 20px;
            line-height: 70px;
        }

        .wrap {
            width: 100%;
            height: 1200px;
        }

        .wrap .aside {
            width: 30%;
            height: 1200px;
            background-color:green;
            float: left;    /*側邊欄浮動*/
        }

        .wrap .content {
            width: 70%;
            height: 1200px;
            background-color: saddlebrown;
            float: left;    /*內容區浮動*/
        }
    </style>
</head>
<body>
    <div id="app">

    </div>
<script type="text/javascript" src="./vue.js"></script>
<script type="text/javascript">
    // 打油詩:先聲子再掛子再用子
    var Vheader = {     // 先聲明頭部組件
        template:`
            <header class="head">
                我是頭部
            </header>
        `
    };

    var Vaside = {     // 聲明側邊欄組件
        template:`
            <div class="aside">
                我是側邊欄
            </div>
        `
    };

    var Vcontent = {     // 聲明內容區組件
        template:`
            <div class="content">
                我是內容區域
            </div>
        `
    };

    // 第一步.聲明入口組件
    /*
        1.頭部組件
        2.側邊欄
        3.內容組件
        4.腳步組件
        以上組件分別掛載到入口組件裏面去。
     */

    var Vmain = {       // 局部組件
        template:`
            <div class='main'>
                <Vheader></Vheader>
                <div class="wrap">
                    <Vaside/>
                    <Vcontent/>
                </div>
            </div>
        `,
        components:{
            // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫:
            Vheader,     // 掛載子組件:頭部組件
            Vaside,      // 掛載子組件:側邊欄組件
            Vcontent
        }
    };

    new Vue({
        el:"#app",   // 注意一個vue裏面只有一個el
        //第三步.使用子組件
        template:"<Vmain></Vmain>",
        data: {

        },
        components:{
            //第二步.聲明變量,掛載子組件  key表示組件名  value表示組件對象
            Vmain:Vmain
        }
    });
</script>
</body>

  組件是可複用的Vue實例,而且帶有一個名字:在這個例子中是 <Vheader>。咱們能夠在一個經過 new Vue 建立的 Vue 根實例中,把這個組件做爲自定義元素來使用。

  顯示效果以下:

  

三、組件使用的總結

  組件使用打油詩:1.聲子   2.掛子   3.用子。

<!-- 1.聲子 -->
var App = {
    template:`
        <div class='app'></div>
    `
};

<!-- 2.掛子 -->
new Vue({
    el:"#app",
    template:"<App/>"
    components:{
        App
    }
}) 

3、經過Prop向子組件傳遞數據

  Prop 是你能夠在組件上註冊的一些自定義特性。當一個值傳遞給一個 prop 特性的時候,它就變成了那個組件實例的一個屬性。那麼就能夠像訪問data中的值同樣來訪問。

  爲了給博文組件傳遞一個標題,咱們能夠用一個 props 選項將其包含在該組件可接受的 prop 列表中:

// 全局組件
Vue.component('blog-post', {
    props: ['title'],
    template: '<h3>{{ title }}</h3>'
})

 

  一個組件默承認以擁有任意數量的 prop,任何值均可以傳遞給任何 prop。在上述模板中,你會發現咱們可以在組件實例中訪問這個值,就像訪問 data 中的值同樣。

  一個 prop 被註冊以後,你就能夠像這樣把數據做爲一個自定義特性傳遞進來:

<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>

一、向子組件傳遞數據示例

<script type="text/javascript">
    var Vheader = {     // 先聲明頭部組件
        template:`
            <header class="head">
                <h3>{{title}}</h3>    // 模板語法渲染title
                <span>{{count}}</span>
                <button @click = 'count+=1'>點擊</button>
            </header>
        `,
        data(){
            return {
                count: 0
            }
        },
        props:['title'],     // props接收title
        methods:{

        }
    };

    var Vmain = {       // 局部組件
        template:`
            <div class='main'>
                <a href="#">{{title}}</a>
                <Vheader v-bind:title = 'title'></Vheader>
                <div class="wrap">
                    <Vaside/>
                    <Vcontent/>
                </div>
            </div>
        `,
        components:{
            // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫:
            Vheader,     // 掛載子組件:頭部組件
            Vaside,      // 掛載子組件:側邊欄組件
            Vcontent
        },
        props:['title']   // 自定義的屬性
    };

    new Vue({
        el:"#app",   // 注意一個vue裏面只有一個el
        //第三步.使用子組件
        template:"<Vmain v-bind:title='text'/>",    // title是屬性名,'text'是數據屬性的名字
        data: {
            text:"alex是SB"   // 在data中設置text,這是數據
        },
        components:{
            //第二步.掛載子組件 key表示組件名  value表示組件對象
            Vmain:Vmain
        }
    });
</script>

  顯示效果以下所示:

  

二、總結流程

(1)在子組件中自定義特性

  props:['自定義的屬性']

  當一個值傳遞給一個prop特性的時候,它就變成了那個組件實例的一個屬性,能夠像訪問data中的值同樣。

(2)要在父組件中導入子組件內部

  須要綁定自定義的屬性<Vheader :title = '父組件中data聲明的數據屬性'/>

(3)注意

  一個組件默承認以擁有任意數量的prop,任何值均可以傳遞任何prop。

  在上述模板中,會發現咱們可以在組件實例中訪問這個值,就像訪問data中的值同樣。

三、父組件向子組件傳遞博客信息示例

<script type="text/javascript">
    var Vcontent = {     // 聲明內容區組件
        template:`
            <div class="content">
                <ul>
                    <li v-for="post in posts" :key="post.id">   // 對應id
                        <h3>個人博客標題:{{post.title}}</h3>
                        <p>個人博客內容:{{post.content}}</p>
                    </li>
                </ul>
            </div>
        `,
        props:['posts']
    };

    var Vmain = {       // 局部組件
        template:`
            <div class='main'>
                <a href="#">{{title}}</a>
                <Vheader v-bind:title = 'title'></Vheader>
                <div class="wrap">
                    <Vaside/>
                    <Vcontent v-bind:posts = 'appPosts' />
                </div>
            </div>
        `,
        components:{
            // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫:
            Vheader,     // 掛載子組件:頭部組件
            Vaside,      // 掛載子組件:側邊欄組件
            Vcontent
        },
        props:['title', 'appPosts']
    };

    new Vue({
        el:"#app",   // 注意一個vue裏面只有一個el
        //第三步.使用子組件
        template:"<Vmain v-bind:title='text' :appPosts = 'posts'/>",    // title對應屬性名
        data: {
            text:"alex是SB",
            posts:[
                {id:1, title:"組件中傳值1", content:"經過prop傳遞數據1"},
                {id:2, title:"組件中傳值2", content:"經過prop傳遞數據22"},
                {id:3, title:"組件中傳值3", content:"經過prop傳遞數據333"}
            ]
        },
        components:{
            //第二步.掛載子組件 key表示組件名  value表示組件對象
            Vmain:Vmain

        }
    });
</script>

  顯示效果:

  

4、子組件經過事件向父級組件發送消息

  開發 <blog-post> 組件時,它的一些功能可能要求咱們和父級組件進行溝通。例如咱們可能會引入一個可訪問性的功能來放大博文的字號,同時讓頁面的其它部分保持默認的字號。

  在其父組件中,咱們能夠經過添加一個 postFontSize 數據屬性來支持這個功能:

new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})

  它能夠在模板中用來控制全部博文的字號:

<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
    ></blog-post>
  </div>
</div>

  在每篇文章正文前添加一個按鈕來放大字號。

  當點擊這個按鈕時,咱們須要告訴父級組件放大全部博文的文本。幸虧 Vue 實例提供了一個自定義事件的系統來解決這個問題。咱們能夠調用內建的 $emit 方法並傳入事件的名字,來向父級組件觸發一個事件:

Vue.component('blog-post', {
    props: ['post'],
    template: `
        <div class="blog-post">
            <h3>{{ post.title }}</h3>
            /*<button>
                Enlarge text
            </button>*/
            <button v-on:click="$emit('enlarge-text')">
                Enlarge text
            </button>
            <div v-html="post.content"></div>
        </div>
    `
})

一、經過自定義事件向父級組件發送消息示例

<script type="text/javascript">
    var Vcontent = {     // 聲明內容區組件
        template:`
            <div class="content">
                <ul>
                    <li v-for="post in posts" :key="post.id">   // 對應id
                        <h3>個人博客標題:{{post.title}}</h3>
                        <p>個人博客內容:{{post.content}}</p>
                    </li>
                </ul>
                <button @click="changeSize">改變字體大小</button>
            </div>
        `,
        props:['posts'],
        methods:{   // 聲明方法
            changeSize(){
                // 經過$emit()方法傳入事件名字,來觸發自定義的事件
                this.$emit('postChangeSize')
            }
        }
    };

    var Vmain = {       // 局部組件
        template:`
            <div class='main' :style="{fontSize:fontsize+'px'}">
                <a href="#">{{title}}</a>
                <Vheader v-bind:title = 'title'></Vheader>
                <div class="wrap">
                    <Vaside/>
                    <Vcontent v-bind:posts = 'appPosts' @postChangeSize="fontsize+=1" />    // 綁定自定義屬性和自定義事件
                </div>
            </div>
        `,
        data(){
            return {
                fontsize:14   // 默認字體大小爲14
            }
        },
        components:{
            // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫:
            Vheader,     // 掛載子組件:頭部組件
            Vaside,      // 掛載子組件:側邊欄組件
            Vcontent
        },
        props:['title', 'appPosts']
    };
    
    new Vue({...)};
</script>

  經過點擊按鈕能夠不斷修改字體大小,具體驅動流程以下所示:

  

  頁面顯示效果以下所示:

  

二、利用$emit第二個參數傳值修改示例以下

  $emit第一個參數是自定義的事件名字,第二個參數就是傳遞的值

    var Vcontent = {     // 聲明內容區組件
        template:`
            <div class="content">
                <ul>
                    <li v-for="post in posts" :key="post.id">   // 對應id
                        <h3>個人博客標題:{{post.title}}</h3>
                        <p>個人博客內容:{{post.content}}</p>
                    </li>
                </ul>
                <button @click="changeSize">改變字體大小</button>
            </div>
        `,
        props:['posts'],
        methods:{   // 聲明方法
            changeSize(){
                // 經過$emit()方法來觸發自定義的事件
                // 第一個參數是自定義的事件名字;第二個參數就是傳遞的值。
          // this指的是vue實例化對象的子類 this.$emit('postChangeSize', 1) } } }; var Vmain = { // 局部組件 template:` <div class='main' :style="{fontSize:fontsize+'px'}"> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts = 'appPosts' @postChangeSize="clickHandler" /> // 綁定自定義屬性和自定義事件 </div> </div> `, methods:{ clickHandler(value){ this.fontsize += this.fontsize+1; } }, data(){ return { fontsize:14 // 默認字體大小爲14 } }, components:{ // 等價於Vheader:Vheader,當兩個詞如出一轍時能夠這樣簡寫: Vheader, // 掛載子組件:頭部組件 Vaside, // 掛載子組件:側邊欄組件 Vcontent }, props:['title', 'appPosts'] };

  組件傳值是vue中最重要的知識點。

三、從子組件傳遞數據到父組件總結

  (1)給子組件中的某個按鈕綁定原生事件,能夠調用內建方法this.$emit('自定義事件名','傳遞的數據'),來向父級組件觸發一個自定義的事件。

  (2)在父組件中的子組件標籤中要綁定自定義的事件

5、全局組件(公共組件)的建立和使用

  全局註冊的組件能夠用在其被註冊以後的任何(經過 new Vue)新建立的 Vue 根實例,也包括其組件樹中的全部子組件的模板中。

一、公共組件示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            padding:0;
            margin:0;
        }
        #head {
            width: 100%;
            height: 80px;
            background-color: purple;
        }
    </style>
</head>
<body>
    <div id="app"></div>
    <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
    <script type="text/javascript">
        // 建立公共組件
        // 第一個參數是公共組件的名字;第二個參數options(與局部組件相同)
        Vue.component('Vbtn', {
            template:`<button>登陸</button>`
        });

        var Vheader = {   // 這裏使用Vheader的緣故是,html5中有header標籤
           template:`<div id="header">
                <Vbtn></Vbtn>
                <Vbtn></Vbtn>
                <Vbtn></Vbtn>
           </div>`
        };

        // 局部組件的使用
        var App = {
            template:`<div>
                <Vheader></Vheader>
            </div>`,
            components: {
                Vheader
            }
        };

        new Vue({
            el: '#app',
            data(){   // 組件中必定是函數

            },
            template:'<App/>',   // 注意必定是閉合標籤
            components: {
                App    // App組件
            }
        })
    </script>
</body>
</html>

  頁面顯示效果以下:

  

二、公共組件使用總結

全局組件的使用:
Vue.component('全局組件的名稱', {
    跟new.Vue()實例化對象中的options是同樣的,可是要注意是:
    不論是公共組件仍是局部組件,data必須是一個函數,函數必定要有返回值(哪怕是一個空對象{})
})

6、內置組件slot(插槽)的用法

  Vue 實現了一套內容分發的 API,這套 API 基於當前的 Web Components 規範草案,將 <slot> 元素做爲承載分發內容的出口。 

一、修改上面公共組件實例,實現內容分發

<head>代碼省略</head>
<body>
    <div id="app"></div>
    <script type="text/javascript" src="./vue.js"></script>
    <script type="text/javascript">
        // 建立公共組件
        // 第一個參數是公共組件的名字;第二個參數options
        Vue.component('Vbtn', {
            template:`<button>
                <slot></slot>
            </button>`
        });

        var Vheader = {   // 這裏使用Vheader的緣故是,html5中有header標籤
           template:`<div id="header">
                <Vbtn>登陸</Vbtn>
                <Vbtn>註冊</Vbtn>
                <Vbtn>提交</Vbtn>
           </div>`
        };
    
    """代碼省略"""
    </script>
</body>
</html>

  若是不使用slot,像上面這麼在模板中添加不一樣的信息是不顯示的。使用vue內置組件slot後顯示效果以下:

  

二、封裝按鈕添加樣式

<script type="text/javascript">
    // 建立公共組件
    // 第一個參數是公共組件的名字;第二個參數options
    Vue.component('Vbtn', {
        template: `<button class="default" :class="type">
                <slot></slot>
            </button>`,
        props: ['type']
    });


    var Vheader = {   // 這裏使用Vheader的緣故是,html5中有header標籤
        template: `<div id="header">
                <Vbtn>登陸</Vbtn>
                <Vbtn>註冊</Vbtn>
                <Vbtn>提交</Vbtn>
                <Vbtn>默認按鈕</Vbtn>
                <Vbtn type="primary">主要按鈕</Vbtn>
                <Vbtn type="success">成功按鈕</Vbtn>
           </div>`
    };

    """代碼省略"""
</script>

(1)給按鈕綁定class  

  這裏應用了vue的v-bind:class來給每一個標籤元素添加class。 

  props:一個 prop 被註冊以後,能夠把數據做爲一個自定義特性傳遞進來。

  所以在「<Vbtn type="success">成功按鈕</Vbtn> 」,中給type定義了一個屬性,經過props組件傳值傳遞到公共組件中,由此就能夠對網頁中全部的按鈕進行一個修飾。

(2)使用elementUI,調整按鈕樣式

  Element - 網站快速成型工具:http://element-cn.eleme.io/#/zh-CN

  

  添加css代碼以下所示:

    <style>
        * {
            padding: 0;
            margin: 0;
        }

        #head {
            width: 100%;
            height: 80px;
            background-color: purple;
        }

        button {
            display: inline-block;
            line-height: 1;
            white-space: nowrap;
            cursor: pointer;
            background: #fff;
            border: 1px solid #dcdfe6;
            border-top-color: rgb(220, 223, 230);
            border-right-color: rgb(220, 223, 230);
            border-bottom-color: rgb(220, 223, 230);
            border-left-color: rgb(220, 223, 230);
            border-color: #dcdfe6;
            color: #606266;
            text-align: center;
            box-sizing: border-box;
            outline: none;
            margin: 0;
            transition: .1s;
            font-weight: 500;
            padding: 12px 20px;
            font-size: 14px;
            border-radius: 4px;
        }

        .primary {
            color: #fff;
            background-color: #409eff;
            border-color: #409eff;
        }

        .success {
            color: #fff;
            background-color: #67c23a;
            border-color: #67c23a;
        }
    </style>

(3)顯示效果以下所示

  

相關文章
相關標籤/搜索