6. vue組件詳解(一)


主要內容:

1. 組件的基本使用

2. 全局組件和局部組件

3. 父組件和子組件 

4. 組件語法糖的寫法

5. 組件data關聯的寫法

6. 父子組件的通信


 

組件系統是 Vue 的一個重要概念,因為它是一種抽象,允許我們使用小型、獨立和通常可復用的組件構建大型應用。幾乎任意類型的應用界面都可以抽象為一個組件樹:

 例如上面頁面, 頁面整體分為三個部分. 我們可以將每一個部分設計為一個組件. 然后將三個組件組成一個頁面. 每一個組件又是由多個小組件構成的. 

組件可以讓模塊可復用性提高. 是一種提倡的用法

一. 組件的基本使用

構建一個組件分為三個部分:

  1. 定義組件
  2. 注冊組件
  3. 使用組件

下面, 我們就從這三個部分來定義一個組件

1. 定義組件

語法: 

Vue.extend({
   template: "" 
})

定義組件使用Vue.extend({})然后在里面定義一個template, 我們看到template的內容是html內容,

為了讓html能夠按照格式顯示, 我們使用``將內容框起來

下面我們來注冊一個組件

const cpnC = Vue.extend({
    template: `<div>
                <h2>aaa</h2>
                <p>組件內容1</p>
                <p>組件內容2</p>
              </div>`
})

2. 注冊組件

語法:

Vue.component("組件名稱", 組件內容)

我們將上面定義的組件進行注冊

// 2. 注冊組件
Vue.component('my-first-comp', cpnC)

3. 使用組件

<div id="app">
   <my-first-comp></my-first-comp>
</div>

直接使用組件名即可

完整源碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
    1. 注冊組件的基本步驟
-->
    <div id="app">
        <my-first-comp></my-first-comp>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        // 1. 創建組件構造器對象
        /**
         * 調用vue.extend()創建一個組件
         * 傳入的template代表我們自定義組件的模板
         * vue2.x以后基本看不到這種寫法, 會直接使用語法糖創建, 但原理還是這個.
         *
         * @type {VueComponent|void}
         */
        const cpnC = Vue.extend({
            template: `<div>
                            <h2>aaa</h2>
                            <p>組件內容1</p>
                            <p>組件內容2</p>
                          </div>`
        })

        // 2. 注冊組件
        Vue.component('my-first-comp', cpnC)

        var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            }
        });
    </script>
</body>
</html>

 

二. 全局組件和局部組件

1. 全局組件

組件有全局組件和局部組件的概念, 如果將一個組件定義在外部就是全局組件

    // 定義一個組件
    const myComp = Vue.extend({
        template: `
            <div>
                <p>你好!!</p>
            </div>
        `
    })
    // 注冊組件(這種方式注冊的組件是全局組件)
    Vue.component('my-comp', myComp)


    let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        }
    });

第一步: 定義了一個組件

第二步:  注冊組件, 在new Vue({})外面注冊的, 是全局組件. 

第三步: 調用組件

<div id="app2">
    <my-comp></my-comp>
</div>

以上定義的就是一個全局組件. 全局組件什么概念呢? 也就是說任何一個Vue實例對象都可以使用. 

下面定義了兩個Vue對象

   let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        },
        components:{
            app1Comp: app1Comp
        }
    });


    let app2 = new Vue({
        el: "#app2"
    })

第一個作用對象是id="app"的div, 第二個作用對象是id="app2"的div

<div id="app">
    <my-comp></my-comp>
    <app1-comp></app1-comp>
</div>

<div id="app2">
    <my-comp></my-comp>
    <app1-comp></app1-comp>
</div>

我們在里面調用組件, 都可以成功. 

全局組件, 一次注冊, 多處調用

2. 局部組件

const app1Comp = Vue.extend({
        template: `
            <div>
                <p>只有app1才能使用的組件</p>
            </div>
        `
    })

    let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        },
        components:{ app1Comp: app1Comp }
    });

我們定義了一個appComp的組件, 但是注冊的時候, 只注冊到了app這個Vue對象里, 那么就只有app能使用,其他vue對象不能使用, 這樣的組件就是局部組件.

局部組件, 哪里注冊, 哪里調用

三. 父組件和子組件

 

 

 像這種有嵌套關系的組件, 就是父子組件. 

那么父組件和子組件如何定義呢?

首先, 定義了一個組件1--comp1

       // 定義組件1
        const comp1 = Vue.extend({
            template: `
            <div>
                <p>組件1</p>
            </div>
            `
        })    

 

然后定義了一個組件2---comp2

        // 定義組件2
        const comp2 = Vue.extend({
            template: `
            <div>
                <h2>組件2</h2>
                <comp1></comp1>
            </div>
            `,
            components:{ // 局部組件  comp1: comp1 }
        })

我們發現, 在組件comp2中注冊了comp1組件, 這里comp2是父組件, comp1是子組件.

最后我們可以把comp2注冊到Vue對象上, 在頁面就可以調用了

    // vue也是一個組件, 是一個root根組件
        var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            },
            components:{
                comp2: comp2
            }
        });

  vue也是一個組件, 是一個root根組件

 

四. 組件語法糖的寫法

在vue2之后, 就很少看到Vue.extend({})的寫法了, 而是使用語法糖

// 語法糖的寫法
Vue.component('comp2', {
    template: '<div><h2>你好, 語法糖寫法!</h2></div>'
})

直接注冊Vue組件

 但是, 這么寫會將html代碼和組件紐在一起, 下面就說說如何將組件和模板分開

 

五. 模板和組件分離

我們有單獨的方式定義模板代碼. 有兩種方法

第一種: script寫法

    <!-- 第一種方式: 使用script -->
    <script type="text/x-template" id="comp2">
        <div>
            <h2>組件和模板分離的寫法1</h2>
        </div>
    </script>

使用script, 需要將type設置為text/x-template. 然后給模板設置一個id, 就代表一個模板了

然后, 注冊模板

Vue.component('comp2', {
     template: comp2
})

接下來就可以調用組件了

<div id="app">
    <comp2></comp2>
</div>

第二種: template寫法

推薦使用第二種寫法

<template id="comp3">
        <div>
            <h3>組件模板分離的第二種寫法</h3>
        </div>
    </template>

使用template標簽, 並為其定義一個id, 組件的定義是一樣的

Vue.component('comp3', {
     template: comp3
})

 

 

五. 組件data關聯的寫法

組件中如果有變量, 怎么辦呢? 我們知道在vue實例中, 變量可以定義在data中, 在組件中也有data屬性, 但這個data屬性是一個方法

例如: 我們定義了一個組件, 其中有一個變量title

<template id="comp1">
        <div>
            <h2>這是一個組件:{{title}}</h2>

        </div>
    </template>

我們在注冊組件的時候, 可以定義一個data函數, 並在返回值輸出title屬性

    Vue.component('comp1', {
            template: comp1,

            data() { return { title: 'vue組件' } }
        })    

這樣就可以拿到屬性的值了. data()方法里面定義一個return返回值, 返回值是一個對象.

這樣寫有些奇怪是不是? 那為什么要寫成方法呢? 

協程組件, 我們的目的是復用, 在多處使用, 如果定義成一個變量值, 在一處修改, 其他調用的的地方也會跟着修改, 這不是我們希望看到的.

而方法是有作用域的, 每一個匿名方法都有自己的地址空間, 所以, 變量是不共享. 達到了相互隔離的目的.

那么, 如果就想共享怎么辦呢? , 我們可以將變量提取出來. 如下寫法:

     // 如何讓所有組件共享變量呢
        let shareData = {
            title: "組件共有的title"
        }

        Vue.component('comp2', {
            template: comp2,
            data(){
                return shareData
            }
        })

這樣每次返回的都是一個地址, 所以, 變量之間是共享的.

六. 父子組件的通信

什么是父子通訊呢? 我們來看看京東官網

 

 

 可以吧這個頁面看成是大組件, 里面有4個子組件構成: 上面是導航, 左邊是欄目導航, 點擊欄目導航右側跟着變化.

我們來分析一下:

數據是在最外層的data里面, 然后循環遍歷獲取左側導航, 當點擊左側導航的時候, 需要將參數傳遞給父組件, 然后發起新的請求, 在渲染到子組件中.

這就是父子通訊. 

父子通訊分為父傳子和子傳父兩種方式

1. 父傳子組件的通訊

父子通訊有兩種方式: 一種是數組, 一種是對象

我們在vue對象中定義了兩個屬性: message和languages

    let app = new Vue({
            el: "#app",
            data: {
                message: "父元素傳遞值給子元素111",
                languages:["go", "php", "python", "java", "c語言"]
            }
        });

然后要在模板中使用這兩個屬性, 要怎么樣才能拿到屬性呢? 

在模板中使用props來接收屬性, 使用props接收屬性有兩種方式:

1) 父子通訊方式---數組方式

第一種是使用數組的方式. 我們在數組中定義兩個變量來接收Vue對象中的兩個屬性.

     Vue.component("comp1", {
            template: "#comp1",
            props:["clanguages", "cmessage"]
        })

然后, 在模板里怎么寫呢? 如下:

    <template id="comp1">
        <div>
            <p>{{cmessage}}</p>
            <ul>
                <li v-for="item in clanguages">{{item}}</li>
            </ul>
        </div>
    </template>

接下來綁定組件變量和vue對象變量的關系, 在哪里調用組件, 就在哪里綁定

 <div id="app">
   <comp1 :clanguages="languages" :cmessage="message"></comp1>
 </div>

綁定的時候其實使用的是v-bind. 將組件的屬性clanguage綁定到vue對象, 可以這么寫:

:clanguages="languages"

這樣就完成了綁定

其實總結有三步驟:

1. 在vue對象中定義屬性

2. 在模板組件中定義與vue屬性接收的變量

3. 在模板中綁定他們之間的關系

2) 父子通訊方式---對象方式

除了使用數組的方式來接收, 還可以使用對象的方式來接收

       // props的對象寫法
        Vue.component('comp2', {
            template: "#comp2",
            props:{
                clanguages: {
                    type: Array, // 設置傳值的類型必須是數組類型
                    default: [], // 默認值是空數組
                    required: true // 如果設置為true, 這個值必須傳, 如果不傳將報錯
                },
                cmessage: {
                    type: String,
                    default: "aa",
                    required: true
                }
            }
        })

props接收的是一個對象, clanguages對象里面可以定義接收數據有三種

  1. 類型type,
  2. 默認值default
  3. 是否是必須有這個屬性required: 這個屬性的含義是, 調用了組件必須要使用這個屬性.

其他使用方法可以參考文章: https://www.cnblogs.com/em2464/p/10418820.html 

2. 子傳父自定義事件

父傳子使用的是定義屬性接收, 而子傳父使用的是定義事件的方式.

就使用上面的例子, 點擊類型傳參給父對象.

Vue.component('comp1', {
    template: "#comp1",
    data() {
        return {
            "types":[
                        {id:1, name:"手機類"},
                        {id:2, name:"日用品"},
                        {id:3, name:"空調類"},
                        {id:4, name:"電腦設備"},
                        {id:5, name:"家用電器"},
            ]
        }
    }
}            

上面定義了一個組件, 組件定義了商城產品的類型

template id="comp1">
        <div>
            <button v-for="item in types" @click="clicktype(item)">{{item.name}}</button>
        </div>
</template>

定義一個組件模板,  循環遍歷商品類型, 並定義了一個點擊事件. clicktype(item)

Vue.component('comp1', {
            template: "#comp1",
            data() {
                return {
                    "types":[
                        {id:1, name:"手機類"},
                        {id:2, name:"日用品"},
                        {id:3, name:"空調類"},
                        {id:4, name:"電腦設備"},
                        {id:5, name:"家用電器"},
                    ]
                }
            },
            methods:{ clicktype(item) { this.$emit('itemclick',item) console.log("點擊類型", item) } }
        })

在點擊事件中, 我們使用this.$emit('itemclick', item)定義了一個事件, 並將元素對象item傳遞給了事件.

那么父組件如何接受這個事件呢? 

父組件需要定義這個事件的監聽. 通常我們都是監聽點擊事件click, 按鍵事件input等自帶事件, 這里需要監聽的是自定義事件

    <div id="app">
        <comp1 @itemclick="itemClick"></comp1>
    </div>

監聽事件使用v-on:事件名稱, 簡寫為@itemclick. 然后在父組件定義時間itemClick

 var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            },
            methods:{
                itemClick(item) { console.log("傳遞事件到父組件", item) }
            }
        });

這樣就可以接收到子組件傳遞過來的數據了.

總結一下:

1. 在模板中定義一個事件, 調用this.$emit('事件名稱', 傳遞參數....)

2. 在模板調用的時候監聽事件. @事件名稱="方法名()"

3. 在父組件中定義方法來接收事件監聽.

 

案例源碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
     <!-- 2. 綁定事件 --> <comp1 @itemclick="itemClick"></comp1> </div> <template id="comp1"> <div> <button v-for="item in types" @click="clicktype(item)">{{item.name}}</button> </div> </template> <script src="../js/vue.js"></script> <script> Vue.component('comp1', { template: "#comp1", data() { return { "types":[ {id:1, name:"手機類"}, {id:2, name:"日用品"}, {id:3, name:"空調類"}, {id:4, name:"電腦設備"}, {id:5, name:"家用電器"}, ] } }, methods:{ clicktype(item) {
            // 1. 注冊事件
this.$emit('itemclick',item) console.log("點擊類型", item) } } }) var app = new Vue({ el: "#app", data: { message: "hello" }, methods:{
          // 3.接收事件 itemClick(item) { console.log(
"傳遞事件到父組件", item) } } }); </script> </body> </html>

效果如下圖

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM