組件 (Component) 是 Vue.js 最強大的功能之一。組件能夠擴展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,Vue.js 的編譯器爲它添加特殊功能。在有些狀況下,組件也能夠是原生 HTML 元素的形式,以 is 特性擴展。javascript
註冊一個全局組件,你可使用 Vue.component(tagName, options)html
<html> <head> <meta charset="utf-8" /> <script type="text/javascript" src='https://unpkg.com/vue'></script> </head> <body> <div id="example"> <my-component></my-component> </div> </body> <script> // 註冊 Vue.component('my-component', { template: '<div>A custom component!</div>' }) // 建立根實例 new Vue({ el: '#example' }) </script> </html>
運行結果:vue
<div id="example"> <div>A custom component!</div> </div>
沒必要在全局註冊每一個組件。經過使用組件實例選項註冊,可使組件僅在另外一個實例/組件的做用域中可用:java
<div id="example-2"> <child-component></child-component> </div> <script> var Child = { template: '<div>A child component!</div>' } new Vue({ el: '#example-2', components: { 'child-component': Child } }) </script>
運行結果:git
<div id="example-2"> <div>A child component!</div> </div>
若是把 child-component 只能用example-2中,不能放到其餘的div中,若是把放到其餘的div中就會報錯。github
<div id="example"> <my-component></my-component> <child-component></child-component> </div>
當使用 DOM 做爲模版時 (例如,將 el 選項掛載到一個已存在的元素上), 你會受到 HTML 的一些限制,由於 Vue 只有在瀏覽器解析和標準化 HTML 後才能獲取模版內容。尤爲像這些元素<ul>,<ol>,<table>,<select>
限制了能被它包裹的元素,而一些像 <option>
這樣的元素只能出如今某些其它元素內部。
在自定義組件中使用這些受限制的元素時會致使一些問題,例如:數組
<table> <my-row>...</my-row> </table>
自定義組件 <my-row> 被認爲是無效的內容,所以在渲染的時候會致使錯誤。變通的方案是使用特殊的 is 屬性:瀏覽器
<table> <tr is="my-row"></tr> </table>
應當注意,若是您使用來自如下來源之一的字符串模板,這些限制將不適用:微信
<script type="text/x-template">
函數
JavaScript 內聯模版字符串
.vue 組件
所以,有必要的話請使用字符串模版。
<div id="example-3"> <simple-counter></simple-counter> <simple-counter></simple-counter> <simple-counter></simple-counter> </div> <script> var data = { counter: 0 } Vue.component('simple-counter', { template: '<button v-on:click="counter += 1">{{ counter }}</button>', // 技術上 data 的確是一個函數了,所以 Vue 不會警告, // 可是咱們返回給每一個組件的實例的卻引用了同一個data對象 data: function () { return data } }) new Vue({ el: '#example-3' }) </script>
因爲這三個組件共享了同一個 data,所以增長一個 counter 會影響全部組件!這不對。咱們能夠經過爲每一個組件返回全新的 data 對象來解決這個問題:
data: function () { //return data return { counter: 0 } }
如今每一個 counter 都有它本身內部的狀態了。
在 Vue 中,父子組件的關係能夠總結爲 props down, events up。父組件經過 props 向下傳遞數據給子組件,子組件經過 events 給父組件發送消息。看看它們是怎麼工做的。
要讓子組件使用父組件的數據,咱們須要經過子組件的 props 選項。
<div id="example-4"> <child message="hello world!"></child> </div> <script> Vue.component('child', { // 聲明 props props: ['message'], // 就像 data 同樣,prop 能夠用在模板內 // 一樣也能夠在 vm 實例中像「this.message」這樣使用 template: '<span>{{ message }}</span>' }) new Vue({ el: '#example-4' }) </script>
運行結果:
<div id="example-4"> <span>hello world!</span> </div>
HTML 特性是不區分大小寫的。因此,當使用的不是字符串模版,camelCased (駝峯式) 命名的 prop 須要轉換爲相對應的 kebab-case (短橫線隔開式) 命名:
<div id="example-5"> <child2 my-message="hello world message!"></child2> </div> <script> Vue.component('child2', { // 聲明 props props: ['myMessage'], // 就像 data 同樣,prop 能夠用在模板內 // 一樣也能夠在 vm 實例中像「this.message」這樣使用 template: '<span>{{ myMessage }}</span>' }) new Vue({ el: '#example-5' }) </script>
運行結果:
<div id="example-5"> <span>hello world message!</span> </div>
若是把child2中的 my-message 改成 myMessage,
<child2 myMessage="hello world message!"></child2>
錯誤提示:
在模板中,要動態地綁定父組件的數據到子模板的 props,與綁定到任何普通的HTML特性相相似,就是用 v-bind。每當父組件的數據變化時,該變化也會傳導給子組件
<div id="example-6"> <input v-model="parentMsg"> <br> <child2 v-bind:my-message="parentMsg"></child2> </div> <script> Vue.component('child2', { // 聲明 props props: ['myMessage'], // 就像 data 同樣,prop 能夠用在模板內 // 一樣也能夠在 vm 實例中像「this.message」這樣使用 template: '<span>{{ myMessage }}</span>' }) new Vue({ el: '#example-6', data:{ parentMsg:'Message from parent', } }) </script>
運行結果:
<!-- 傳遞了一個字符串 "1" --> <comp some-prop="1"></comp>
由於它是一個字面 prop,它的值是字符串 "1" 而不是 number。若是想傳遞一個實際的 number,須要使用 v-bind,從而讓它的值被看成 JavaScript 表達式計算:
<div id="example-7"> <comp v-bind:some-prop="1"></comp> </div> <script> Vue.component('comp', { // 聲明 props props: ['someProp'], template: "<span>{{ someProp +'----'+ typeof someProp }}</span>" }) new Vue({ el: '#example-7' }) </script>
prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,可是不會反過來。這是爲了防止子組件無心修改了父組件的狀態——這會讓應用的數據流難以理解。
咱們能夠爲組件的 props 指定驗證規格。若是傳入的數據不符合規格,Vue 會發出警告。當組件給其餘人使用時,這頗有用。
要指定驗證規格,須要用對象的形式,而不能用字符串數組:
<div id="example-8"> <example prop-a="11231" prop-c='asda'></example> </div> <script> Vue.component('example', { props: { // 基礎類型檢測 (`null` 意思是任何類型均可以) 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 value > 10 } } }, template: "<span> {{'propA: '+ propA +' propC:'+propC}} </span>" }) new Vue({ el: '#example-8' }) </script>
錯誤提示:
propA 類型是number,而咱們傳遞給它的是個字符串,須要以下修改
<example v-bind:prop-a="11231" prop-c='asda'></example> // :prop-a 是 v-bind:prop-a的縮寫 <example :prop-a="11231" prop-c='asda'></example>
若是把prop-c去掉,格式以下
<example :prop-a="11231" </example>
錯誤提示:
這是因爲propC required: true 是必傳的。
type 能夠是下面原生構造器:
String
Number
Boolean
Function
Object
Array
Symbol
type 也能夠是一個自定義構造器函數,使用 instanceof 檢測。
當 prop 驗證失敗,Vue 會在拋出警告 (若是使用的是開發版本)。注意 props 會在組件實例建立以前進行校驗,因此在 default 或 validator 函數裏,諸如 data、computed 或 methods 等實例屬性還沒法使用。
所謂非 prop 屬性,就是它能夠直接傳入組件,而不須要定義相應的 prop。
明確給組件定義 prop 是傳參的推薦方式,但組件的做者並不總能預見到組件被使用的場景。因此,組件能夠接收任意傳入的屬性,這些屬性都會被添加到組件的根元素上。
例如,第三方組件 bs-date-input,當它要和一個 Bootstrap 插件互操做時,須要在這個第三方組件的 input 上添加 data-3d-date-picker 屬性,這時能夠把屬性直接添加到組件上 (不須要事先定義 prop):
<bs-date-input data-3d-date-picker="true"></bs-date-input>
添加屬性 data-3d-date-picker="true" 以後,它會被自動添加到 bs-date-input 的根元素上
<div id="example-9"> <bs-date-input data-3d-date-picker="true" class="date-picker-theme-dark"></bs-date-input> </div> <script> Vue.component('bs-date-input',{ template: '<input type="date" class="form-control">' }) new Vue({ el: '#example-9' }) </script>
運行結果:
<div id="example-9"> <input type="date" class="form-control date-picker-theme-dark" data-3d-date-picker="true"> </div>
對於多數特性來講,傳遞給組件的值會覆蓋組件自己設定的值。即例如傳遞 type="large" 將會覆蓋 type="date" 且有可能破壞該組件!索性咱們對待 class 和 style 特性會更聰明一些,這兩個特性的值都會作合併 (merge) 操做,讓最終生成的值爲:form-control date-picker-theme-dark。
社羣品牌:從零到壹全棧部落
定位:尋找共好,共同窗習,持續輸出全棧技術社羣
業界榮譽:IT界的邏輯思惟
文化:輸出是最好的學習方式
官方公衆號:全棧部落
社羣發起人:春哥(從零到壹創始人,交流微信:liyc1215)
技術交流社區:全棧部落BBS
全棧部落完整系列教程:全棧部落完整電子書學習筆記
關注全棧部落官方公衆號,每晚十點接收系列原創技術推送 |
---|