在正式開始講解組件以前,咱們先來看一個簡單的例子: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
該方法的第一個參數是組件名,第二個參數是選項對象,對象中包含兩個屬性,data
和 template
java
屬性 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 } })
若是但願 ComponentA
在 ComponentB
中可用,咱們須要換一種寫法:
var ComponentA = { /* ... */ } var ComponentB = { components: { 'component-a': ComponentA }, // ... }
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學習筆記 】