VUE快速入門新的——元件之間傳遞資料(1. Prop)
晚上好大家,元件我們在上邊文章中已經說過了,對大家還是有點幫助的應該。哈哈~~ 今天我們說一下關於元件之間資料是怎樣傳遞的?不難看出,其實元件之間的資料通訊,簡單的可以分為三類。
- 父元件向子元件傳遞
- 子元件向父元件傳遞
- 平級之間的元件資料傳遞
之前也有說到,父元件可以通過props向下傳遞資料給子元件,子元件可以通過events向上給父元件傳遞資料,下面我們就來詳細的看一下。
我們一步步來看
Prop
使用prop傳遞資料
其實通過不斷的學習,我們會發現,其實元件例項的作用域是孤立的。這意味著不能(同時也是不應該)在子元件的模板內直接引用父元件的資料。要讓子元件使用父元件的資料,我們需要通過子元件的props選項。
子元件要顯式地用props
Vue.component('child', {
// 宣告 props
props: ['message'],
// 就像 data 一樣,prop 可以用在模板內
// 同樣也可以在 vm 例項中像“this.message”這樣使用
template: '<span>{{ message }}</span>'
})
然後我們就可以像下邊這樣向它傳入一個字串:
<child message="hello!"></child>
結果就是可想而知的輸出hello!
camelCase vs kebab-case
HTML特性是不區分大小寫的。所以,當使用的不是字串模板時,camelCase(駝峰式)命名的prop需要轉換為相對應的kebab-case(短橫線隔開式)命名:
Vue.component('child', {
// camelCase in JavaScript
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
<!-- kebab-case in HTML -->
<child my-message="hello!"></child>
如果我們使用的是字串模板,那麼就沒有了這些限制。
動態prop
在模板中,要動態的繫結父元件的資料到子元件的props,與繫結的任何普通的html特性相類似,就是使用v-bind
。每當父元件的資料發生變化時,改變化也會傳遞給子元件:
<div>
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>
使用v-bind
縮寫方法寫起來更簡單:
<child :my-message="parentMsg"></child>
此時,我們就做到了動態繫結
字面量法 VS 動態語法
我們剛接觸Vue經常犯一個錯誤,使用字面量語法傳遞資料:
<!-- 傳遞了一個字串 "1" -->
<comp some-prop="1"></comp>
因為它是一個字面 prop,它的值是字串 “1” 而不是 number。如果想傳遞一個實際的 number,需要使用v-bind
,從而讓它的值被當作 JavaScript 表示式計算:
<!-- 傳遞實際的 number -->
<comp v-bind:some-prop="1"></comp>
單向資料流
prop 是單向繫結的:當父元件的屬性變化時,將傳導給子元件,但是不會反過來。這是為了防止子元件無意修改了父元件的狀態——這會讓應用的資料流難以理解。
另外,每次父元件更新時,子元件的所有 prop 都會更新為最新值。這意味著你不應該在子元件內部改變 prop。如果你這麼做了,Vue 會在控制檯給出警告。
為什麼我們會有修改 prop 中資料的衝動呢?通常是這兩種原因:
- prop 作為初始值傳入後,子元件想把它當作區域性資料來用;
- prop 作為初始值傳入,由子元件處理成其它資料輸出。
對於這兩種原因,正確的應對方式為:
1.定義一個區域性變數,並用 prop 的值初始化它:
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
- 定義一個計算屬性,處理 prop 的值並返回。
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
注意在 JavaScript 中物件和陣列是引用型別,指向同一個記憶體空間,如果 prop 是一個物件或陣列,在子元件內部改變它會影響父元件的狀態。
prop驗證
我們可以為元件的 props 指定驗證規格。如果傳入的資料不符合規格,Vue 會發出警告。當元件給其他人使用時,這很有用。
要指定驗證規格,需要用物件的形式,而不能用字串陣列:
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
}
}
}
})
type
可以使下面原生構造器:
- String
- Number
- Boolean
- Function
- Object
- Array
- Symbol
type
也可以是一個自定義構造器函式,使用intaceof
檢測。
當 prop 驗證失敗,Vue 會在丟擲警告 (如果使用的是開發版本)。注意 props 會在元件例項建立之前進行校驗,所以在default
或validator
函式裡,諸如data
、computed
或methods
等例項屬性還無法使用。
非Prop屬性
所謂非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
的根元素上
替換/覆蓋現有屬性
我們來想象一下這是 bs-date-input
的模板:
<input type="date" class="form-control">
為了給該日期選擇器外掛增加一個特殊的主題,我們可能需要增加一個特殊的 class,比如:
<bs-date-input
data-3d-date-picker="true"
class="date-picker-theme-dark"
></bs-date-input>
在這個 case 當中,我們定義了兩個不一樣的 class
的值:
form-control
,來自元件的模板date-picker-theme-dark
,從父元件傳進來的
對於多數特性來說,傳遞給元件的值會覆蓋元件本身設定的值。即例如傳遞 type="large"
將會覆蓋 type="date"
且有可能破壞該元件!索性我們對待 class
和 style
特性會更聰明一些,這兩個特性的值都會做合併 (merge) 操作,讓最終生成的值為:form-control
date-picker-theme-dark
。
至此呢,父元件向子元件傳遞資料我們也說的差不多的了,後邊我們再來分析子元件向父元件傳遞資料以及兩個元件(平級元件)的資料是怎樣進行傳遞的。