天天看點

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

實際應用項目:http://github.crmeb.net/u/long

主要内容:

1. 元件的基本使用

2. 全局元件和局部元件

3. 父元件和子元件 

4. 元件文法糖的寫法

5. 元件data關聯的寫法

6. 父子元件的通信

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

元件可以讓子產品可複用性提高. 是一種提倡的用法

一. 元件的基本使用

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

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

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

1. 定義元件

文法: 

Vue.extend({
   template: "" 
})      

定義元件使用Vue.extend({})然後在裡面定義一個template, 我們看到template的内容是html内容,

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

下面我們來注冊一個元件

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
const cpnC = Vue.extend({
    template: `<div>
                <h2>aaa</h2>
                <p>元件内容1</p>
                <p>元件内容2</p>
              </div>`
})      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

2. 注冊元件

文法:

Vue.component("元件名稱", 元件内容)      

我們将上面定義的元件進行注冊

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

3. 使用元件

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

直接使用元件名即可

完整源碼:

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
<!DOCTYPE html>
<html >
<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>      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

二. 全局元件和局部元件

1. 全局元件

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
// 定義一個元件
    const myComp = Vue.extend({
        template: `
            <div>
                <p>你好!!</p>
            </div>
        `
    })
    // 注冊元件(這種方式注冊的元件是全局元件)
    Vue.component('my-comp', myComp)


    let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        }
    });      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

第一步: 定義了一個元件

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

第三步: 調用元件

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

以上定義的就是一個全局元件. 全局元件什麼概念呢? 也就是說任何一個Vue執行個體對象都可以使用. 

下面定義了兩個Vue對象

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        },
        components:{
            app1Comp: app1Comp
        }
    });


    let app2 = new Vue({
        el: "#app2"
    })      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
<div id="app">
    <my-comp></my-comp>
    <app1-comp></app1-comp>
</div>

<div id="app2">
    <my-comp></my-comp>
    <app1-comp></app1-comp>
</div>      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

我們在裡面調用元件, 都可以成功. 

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

2. 局部元件

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
const app1Comp = Vue.extend({
        template: `
            <div>
                <p>隻有app1才能使用的元件</p>
            </div>
        `
    })

    let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        },
        components:{
            app1Comp: app1Comp
        }
    });      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

局部元件, 哪裡注冊, 哪裡調用

三. 父元件和子元件

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

那麼父元件和子元件如何定義呢?

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
// 定義元件1
        const comp1 = Vue.extend({
            template: `
            <div>
                <p>元件1</p>
            </div>
            `
        })          
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

然後定義了一個元件2---comp2

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
// 定義元件2
        const comp2 = Vue.extend({
            template: `
            <div>
                <h2>元件2</h2>
                <comp1></comp1>
            </div>
            `,
            components:{ // 局部元件
                comp1: comp1
            }
        })      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
// vue也是一個元件, 是一個root根元件
        var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            },
            components:{
                comp2: comp2
            }
        });      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

  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開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
Vue.component('comp1', {
            template: comp1,

            data() {
                return {
                    title: 'vue元件'
                }
            }
        })          
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

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

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

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

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
// 如何讓所有元件共享變量呢
        let shareData = {
            title: "元件共有的title"
        }

        Vue.component('comp2', {
            template: comp2,
            data(){
                return shareData
            }
        })      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

六. 父子元件的通信

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

我們來分析一下:

資料是在最外層的data裡面, 然後循環周遊擷取左側導航, 當點選左側導航的時候, 需要将參數傳遞給父元件, 然後發起新的請求, 在渲染到子元件中.

這就是父子通訊. 

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

1. 父傳子元件的通訊

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

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
let app = new Vue({
            el: "#app",
            data: {
                message: "父元素傳遞值給子元素111",
                languages:["go", "php", "python", "java", "c語言"]
            }
        });      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

然後要在模闆中使用這兩個屬性, 要怎麼樣才能拿到屬性呢? 

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

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

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

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

然後, 在模闆裡怎麼寫呢? 如下:

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
<template id="comp1">
        <div>
            <p>{{cmessage}}</p>
            <ul>
                <li v-for="item in clanguages">{{item}}</li>
            </ul>
        </div>
    </template>      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

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

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

:clanguages="languages"      

這樣就完成了綁定

其實總結有三步驟:

1. 在vue對象中定義屬性

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

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

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

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
// props的對象寫法
        Vue.component('comp2', {
            template: "#comp2",
            props:{
                clanguages: {
                    type: Array, // 設定傳值的類型必須是數組類型
                    default: [], // 預設值是空數組
                    required: true // 如果設定為true, 這個值必須傳, 如果不傳将報錯
                },
                cmessage: {
                    type: String,
                    default: "aa",
                    required: true
                }
            }
        })      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

props接收的是一個對象, clanguages對象裡面可以定義接收資料有三種

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

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

2. 子傳父自定義事件

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

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
Vue.component('comp1', {
    template: "#comp1",
    data() {
        return {
            "types":[
                        {id:1, name:"手機類"},
                        {id:2, name:"日用品"},
                        {id:3, name:"空調類"},
                        {id:4, name:"電腦裝置"},
                        {id:5, name:"家用電器"},
            ]
        }
    }
}                  
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

上面定義了一個元件, 元件定義了商城産品的類型

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

定義一個元件模闆,  循環周遊商品類型, 并定義了一個點選事件. clicktype(item)

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
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)
                }
            }
        })      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

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

那麼父元件如何接受這個事件呢? 

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

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

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

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            },
            methods:{
                itemClick(item) {
                    console.log("傳遞事件到父元件", item)
                }
            }
        });      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

這樣就可以接收到子元件傳遞過來的資料了.

總結一下:

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

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

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

案例源碼:

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信
<!DOCTYPE html>
<html >
<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>      
前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信

效果如下圖

前端vue開發之----vue元件詳解(一)一. 元件的基本使用二. 全局元件和局部元件三. 父元件和子元件四. 元件文法糖的寫法五. 模闆群組件分離五. 元件data關聯的寫法六. 父子元件的通信