6. vue元件詳解(一)

盛開的太陽發表於2021-02-25

主要內容:

1. 元件的基本使用

2. 全域性元件和區域性元件

3. 父元件和子元件 

4. 元件語法糖的寫法

5. 元件data關聯的寫法

6. 父子元件的通訊


 

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

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物件不能使用, 這樣的元件就是區域性元件.

區域性元件, 哪裡註冊, 哪裡呼叫

三. 父元件和子元件

6. 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
            }
        })

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

六. 父子元件的通訊

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

6. vue元件詳解(一)

 

 

 可以吧這個頁面看成是大元件, 裡面有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>

效果如下圖

6. vue元件詳解(一)

 

 

相關文章