Vue學習筆記(七) 組件

0、入門

在正式開始講解組件以前,咱們先來看一個簡單的例子:javascript

<!DOCTYPE html>
<html>

<head>
    <title>Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
    <div id="app">
        <button-counter></button-counter>
    </div>

    <script>
        Vue.component('button-counter', {
            data: function () {
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">{{ count }} times</button>'
        })
        new Vue({
            el: '#app'
        })
    </script>
</body>


</html>

下面咱們詳細解讀一下上面這份代碼:html

Vue.component('button-counter', {
    data: function () {
        return {
            count: 0
        }
    },
    template: '<button v-on:click="count++">{{ count }} times</button>'
})

咱們首先經過全局方法 Vue.component() 建立了一個名爲 button-counter 的全局組件vue

該方法的第一個參數是組件名,第二個參數是選項對象,對象中包含兩個屬性,datatemplatejava

屬性 data 是一個 返回對象的函數,用於儲存動態變化的數據npm

之因此定義爲函數,是由於組件可能被用來建立多個實例,若定義爲對象,則全部實例將會共享同一份數據對象數組

屬性 template 是一個 模板字符串,用於定義組件的 HTML 代碼app

須要注意的是,組件必須是單根元素,也就是說模板的內容必須包裹在一個父元素內函數

<div id="app">
    <button-counter></button-counter>
</div>

而後,咱們就能夠在一個經過 new Vue() 建立的根實例中,把這個組件看成自定義元素使用學習

好,在對組件有了一個初步的理解以後,下面咱們再來進行詳細的學習ui

一、組件註冊

組件是可複用的 Vue 實例,在使用組件前,咱們首先要對組件進行註冊,以便於 Vue 可以識別出來

(1)組件註冊的參數有兩個,分別是 組件名選項對象

  • 組件名

定義組件名的方式有兩種,分別是 kebab-case(短橫線分隔命名)和 PascalCase(首字母大寫命名)

kebab-case:在引用時,須要使用 kebab-case

PascalCase:在模板中使用時,兩種命名法均可用;在 DOM 中使用時,只有 kebab-case 是有效的

  • 選項對象

該對象接收的選項與 new Vue() 接收的選項相似,僅有的例外是像 el 這樣的根實例特有的選項

(2)組件註冊的方式有兩種,分別是 全局註冊局部註冊

  • 全局註冊

咱們可使用全局方法 Vue.component() 進行全局註冊,該方法的第一個參數是組件名,第二個參數是選項對象

全局註冊的組件能夠在任何新建立的根實例中使用

Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })

new Vue({ el: '#app' })
  • 局部註冊

咱們能夠在建立根實例時使用選項 components 進行局部註冊,它是一個對象,鍵是組件名,值是選項對象

局部註冊的組件不能夠在其子組件中使用,也就是說,在下例中的兩個組件不能夠在各自內部相互調用

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }

new Vue({
    el: '#app',
    components: {
        'component-a': ComponentA,
        'component-b': ComponentB
    }
})

若是但願 ComponentAComponentB 中可用,咱們須要換一種寫法:

var ComponentA = { /* ... */ }

var ComponentB = {
  components: {
    'component-a': ComponentA
  },
  // ...
}

二、向子組件傳遞數據 —— prop

prop 是在組件註冊的一些自定義特性,當一個值傳遞給一個 prop 特性時,它就變成那個組件實例的一個屬性

(1)傳遞靜態 prop

在下例中,咱們給 prop 傳遞了一個靜態的值,Title Here

<!DOCTYPE html>
<html>

<head>
    <title>Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
    <div id="app">
        <title-item title="Title Here"></title-item>
    </div>

    <script>
        Vue.component('title-item', {
            props: ['title'],
            template: '<h3>{{ title }}</h3>'
        })
        new Vue({
            el: '#app'
        })
    </script>
</body>


</html>

(2)傳遞動態 prop

在下例中,咱們經過 v-bind 給 prop 綁定了一個動態的對象,content

<!DOCTYPE html>
<html>

<head>
    <title>Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
    <div id="app">
        <title-item v-bind:title="content.title"></title-item>
    </div>

    <script>
        Vue.component('title-item', {
            props: ['title'],
            template: '<h3>{{ title }}</h3>'
        })
        new Vue({
            el: '#app',
            data: {
                content: {
                    'title': 'Title Here'
                }
            }
        })
    </script>
</body>


</html>

(3)prop 類型與 prop 驗證

在上面的兩個例子中,props 都是一個字符串數組,其中的每個 prop 都是一個字符串

但事實上,prop 還能夠是其它類型

這時咱們能夠用對象列出 prop,其中對象的鍵是 prop 的名稱,對象的值是 prop 的類型

Vue.component('my-component', {
    props: {
        propA: String,
        propB: Number,
        propC: Boolean,
        propD: Array,
        propE: Object,
        propF: Function
        // ...
    },
    // ...
})

既然 prop 有了類型,就要判斷 prop 是否符合類型,咱們能夠定製 prop 的驗證方式(如下是官方文檔中的一個例子)

Vue.component('my-component', {
  props: {
    // 基礎的類型檢查 (`null` 和 `undefined` 會經過任何類型驗證)
    propA: Number,
    // 多個可能的類型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 帶有默認值的數字
    propD: {
      type: Number,
      default: 100
    },
    // 帶有默認值的對象
    propE: {
      type: Object,
      // 對象或數組默認值必須從一個工廠函數獲取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函數
    propF: {
      validator: function (value) {
        // 這個值必須匹配下列字符串中的一個
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

當 prop 驗證失敗時,(開發環境構建版本的) Vue 將會產生一個控制檯的警告

三、向父組件傳遞數據 —— 自定義事件

prop 是一個單向下行綁定,即父級 prop 的更新會向下流動到子組件中,但反過來不行

若是子組件要把數據傳遞給父組件,則須要使用自定義事件

父組件能夠經過 v-on 監聽子組件實例的任意事件,而子組件能夠經過 $emit() 觸發事件

(1)監聽子組件事件

<!DOCTYPE html>
<html>

<head>
    <title>Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

<body>
    <div id="app">
        <p>{{ total }}</p>
        <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>

    <script>
        Vue.component('button-counter', {
            template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
            data: function () {
                return {
                    counter: 0
                }
            },
            methods: {
                incrementHandler: function () {
                    this.counter += 1
                    this.$emit('increment')
                }
            },
        })
        new Vue({
            el: '#app',
            data: {
                total: 0
            },
            methods: {
                incrementTotal: function () {
                    this.total += 1
                }
            }
        })
    </script>
</body>


</html>

下面讓咱們來詳細解讀一下上面這段代碼:

Vue.component('button-counter', {
    template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    data: function () {
        return {
            counter: 0
        }
    },
    methods: {
        incrementHandler: function () {
            this.counter += 1
            this.$emit('increment')
        }
    },
})

首先,咱們定義了一個名爲 button-counter 的組件

子組件 button-counter 使用 v-on 監聽原生事件 click,該事件的處理函數是 incrementHandler()

incrementHandler() 中,首先將 counter(子組件中的數據)的值加 1,而後觸發自定義事件 increment

<div id="app">
    <p>{{ total }}</p>
    <button-counter v-on:increment="incrementTotal"></button-counter>
</div>
new Vue({
    el: '#app',
    data: {
        total: 0
    },
    methods: {
        incrementTotal: function () {
            this.total += 1
        }
    }
})

根組件一樣是經過 v-on 監聽自定義事件 increment,該事件的處理函數是 incrementTotal()

incrementTotal() 中,將 total(根組件中的數據)的值加 1

(2)經過事件拋出一個值

咱們能夠在 $emit() 函數的第二個參數中拋出一個值

Vue.component('button-counter', {
    template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
    data: function () {
        return {
            counter: 0
        }
    },
    methods: {
        incrementHandler: function () {
            this.counter += 1
            this.$emit('increment', 2)
        }
    },
})

並在事件處理函數的第一個參數中接收該值

new Vue({
    el: '#app',
    data: {
        total: 0
    },
    methods: {
        incrementTotal: function (value) {
            this.total += value
        }
    }
})

【 閱讀更多 Vue 系列文章,請看 Vue學習筆記

相關文章
相關標籤/搜索