此章節假設你(nǐ)已經看(kàn)過了(le)組件基礎。若你(nǐ)還不了(le)解組件是什(shén)麽,請(qǐng)先閱讀該章節。
Props 聲明(míng)
一個組件需要顯式聲明(míng)它所接受的 props,這(zhè)樣 Vue 才能(néng)知(zhī)道(dào)外(wài)部傳入的哪些(xiē)是 props,哪些(xiē)是透傳 attribute (關于透傳 attribute,我們會(huì)在專門(mén)的章節中讨論)。
props 需要使用(yòng) props 選項來(lái)定義:
js
export default {
props: ['foo'],
created() {
// props 會(huì)暴露到(dào) `this` 上(shàng)
console.log(this.foo)
}
}
除了(le)使用(yòng)字符串數組來(lái)聲明(míng) prop 外(wài),還可以使用(yòng)對(duì)象的形式:
js
export default {
props: {
title: String,
likes: Number
}
}
對(duì)于以對(duì)象形式聲明(míng)中的每個屬性,key 是 prop 的名稱,而值則是該 prop 預期類型的構造函數。比如,如果要求一個 prop 的值是 number 類型,則可使用(yòng) Number 構造函數作(zuò)爲其聲明(míng)的值。
對(duì)象形式的 props 聲明(míng)不僅可以一定程度上(shàng)作(zuò)爲組件的文(wén)檔,而且如果其他(tā)開(kāi)發者在使用(yòng)你(nǐ)的組件時(shí)傳遞了(le)錯誤的類型,也(yě)會(huì)在浏覽器控制台中抛出警告。我們将在本章節稍後進一步讨論有關 prop 校驗的更多細節。
TypeScript 用(yòng)戶請(qǐng)參考:爲組件 Props 标注類型
傳遞 prop 的細節
Prop 名字格式
如果一個 prop 的名字很(hěn)長,應使用(yòng) camelCase 形式,因爲它們是合法的 JavaScript 标識符,可以直接在模闆的表達式中使用(yòng),也(yě)可以避免在作(zuò)爲屬性 key 名時(shí)必須加上(shàng)引号。
js
export default {
props: {
greetingMessage: String
}
}
template
<span>{{ greetingMessage }}</span>
雖然理(lǐ)論上(shàng)你(nǐ)也(yě)可以在向子組件傳遞 props 時(shí)使用(yòng) camelCase 形式 (使用(yòng) DOM 模闆時(shí)例外(wài)),但(dàn)實際上(shàng)爲了(le)和(hé) HTML attribute 對(duì)齊,我們通常會(huì)将其寫爲 kebab-case 形式:
template
<MyComponent greeting-message="hello" />
對(duì)于組件名我們推薦使用(yòng) PascalCase,因爲這(zhè)提高(gāo)了(le)模闆的可讀性,能(néng)幫助我們區(qū)分 Vue 組件和(hé)原生 HTML 元素。然而對(duì)于傳遞 props 來(lái)說,使用(yòng) camelCase 并沒有太多優勢,因此我們推薦更貼近 HTML 的書寫風(fēng)格。
靜态 vs. 動态 Prop
至此,你(nǐ)已經見過了(le)很(hěn)多像這(zhè)樣的靜态值形式的 props:
template
<BlogPost title="My journey with Vue" />
相應地,還有使用(yòng) v-bind 或縮寫 : 來(lái)進行動态綁定的 props:
template
<!-- 根據一個變量的值動态傳入 -->
<BlogPost :title="post.title" />
<!-- 根據一個更複雜(zá)表達式的值動态傳入 -->
<BlogPost :title="post.title + ' by ' + post.author.name" />
傳遞不同的值類型
在上(shàng)述的兩個例子中,我們隻傳入了(le)字符串值,但(dàn)實際上(shàng)任何類型的值都可以作(zuò)爲 props 的值被傳遞。
Number
template
<!-- 雖然 `42` 是個常量,我們還是需要使用(yòng) v-bind -->
<!-- 因爲這(zhè)是一個 JavaScript 表達式而不是一個字符串 -->
<BlogPost :likes="42" />
<!-- 根據一個變量的值動态傳入 -->
<BlogPost :likes="post.likes" />
Boolean
template
<!-- 僅寫上(shàng) prop 但(dàn)不傳值,會(huì)隐式轉換爲 `true` -->
<BlogPost is-published />
<!-- 雖然 `false` 是靜态的值,我們還是需要使用(yòng) v-bind -->
<!-- 因爲這(zhè)是一個 JavaScript 表達式而不是一個字符串 -->
<BlogPost :is-published="false" />
<!-- 根據一個變量的值動态傳入 -->
<BlogPost :is-published="post.isPublished" />
Array
template
<!-- 雖然這(zhè)個數組是個常量,我們還是需要使用(yòng) v-bind -->
<!-- 因爲這(zhè)是一個 JavaScript 表達式而不是一個字符串 -->
<BlogPost :comment-ids="[234, 266, 273]" />
<!-- 根據一個變量的值動态傳入 -->
<BlogPost :comment-ids="post.commentIds" />
Object
template
<!-- 雖然這(zhè)個對(duì)象字面量是個常量,我們還是需要使用(yòng) v-bind -->
<!-- 因爲這(zhè)是一個 JavaScript 表達式而不是一個字符串 -->
<BlogPost
:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
/>
<!-- 根據一個變量的值動态傳入 -->
<BlogPost :author="post.author" />
使用(yòng)一個對(duì)象綁定多個 prop
如果你(nǐ)想要将一個對(duì)象的所有屬性都當作(zuò) props 傳入,你(nǐ)可以使用(yòng)沒有參數的 v-bind,即隻使用(yòng) v-bind 而非 :prop-name。例如,這(zhè)裏有一個 post 對(duì)象:
js
export default {
data() {
return {
post: {
id: 1,
title: 'My Journey with Vue'
}
}
}
}
以及下(xià)面的模闆:
template
<BlogPost v-bind="post" />
而這(zhè)實際上(shàng)等價于:
template
<BlogPost :id="post.id" :title="post.title" />
單向數據流
所有的 props 都遵循着單向綁定原則,props 因父組件的更新而變化,自(zì)然地将新的狀态向下(xià)流往子組件,而不會(huì)逆向傳遞。這(zhè)避免了(le)子組件意外(wài)修改父組件的狀态的情況,不然應用(yòng)的數據流将很(hěn)容易變得混亂而難以理(lǐ)解。
另外(wài),每次父組件更新後,所有的子組件中的 props 都會(huì)被更新到(dào)最新值,這(zhè)意味着你(nǐ)不應該在子組件中去更改一個 prop。若你(nǐ)這(zhè)麽做了(le),Vue 會(huì)在控制台上(shàng)向你(nǐ)抛出警告:
js
export default {
props: ['foo'],
created() {
// ❌ 警告!prop 是隻讀的!
this.foo = 'bar'
}
}
導緻你(nǐ)想要更改一個 prop 的需求通常來(lái)源于以下(xià)兩種場景:
prop 被用(yòng)于傳入初始值;而子組件想在之後将其作(zuò)爲一個局部數據屬性。在這(zhè)種情況下(xià),最好(hǎo)是新定義一個局部數據屬性,從(cóng) props 上(shàng)獲取初始值即可:
js
export default {
props: ['initialCounter'],
data() {
return {
// 計(jì)數器隻是将 this.initialCounter 作(zuò)爲初始值
// 像下(xià)面這(zhè)樣做就使 prop 和(hé)後續更新無關了(le)
counter: this.initialCounter
}
}
}
需要對(duì)傳入的 prop 值做進一步的轉換。在這(zhè)種情況中,最好(hǎo)是基于該 prop 值定義一個計(jì)算(suàn)屬性:
js
export default {
props: ['size'],
computed: {
// 該 prop 變更時(shí)計(jì)算(suàn)屬性也(yě)會(huì)自(zì)動更新
normalizedSize() {
return this.size.trim().toLowerCase()
}
}
}
更改對(duì)象 / 數組類型的 props
當對(duì)象或數組作(zuò)爲 props 被傳入時(shí),雖然子組件無法更改 props 綁定,但(dàn)仍然可以更改對(duì)象或數組内部的值。這(zhè)是因爲 JavaScript 的對(duì)象和(hé)數組是按引用(yòng)傳遞,而對(duì) Vue 來(lái)說,禁止這(zhè)樣的改動,雖然可能(néng)生效,但(dàn)有很(hěn)大(dà)的性能(néng)損耗,比較得不償失。
這(zhè)種更改的主要缺陷是它允許了(le)子組件以某種不明(míng)顯的方式影響父組件的狀态,可能(néng)會(huì)使數據流在将來(lái)變得更難以理(lǐ)解。在最佳實踐中,你(nǐ)應該盡可能(néng)避免這(zhè)樣的更改,除非父子組件在設計(jì)上(shàng)本來(lái)就需要緊密耦合。在大(dà)多數場景下(xià),子組件應該抛出一個事(shì)件來(lái)通知(zhī)父組件做出改變。
Prop 校驗
Vue 組件可以更細緻地聲明(míng)對(duì)傳入的 props 的校驗要求。比如我們上(shàng)面已經看(kàn)到(dào)過的類型聲明(míng),如果傳入的值不滿足類型要求,Vue 會(huì)在浏覽器控制台中抛出警告來(lái)提醒使用(yòng)者。這(zhè)在開(kāi)發給其他(tā)開(kāi)發者使用(yòng)的組件時(shí)非常有用(yòng)。
要聲明(míng)對(duì) props 的校驗,你(nǐ)可以向 props 選項提供一個帶有 props 校驗選項的對(duì)象,例如:
js
export default {
props: {
// 基礎類型檢查
//(給出 `null` 和(hé) `undefined` 值則會(huì)跳過任何類型檢查)
propA: Number,
// 多種可能(néng)的類型
propB: [String, Number],
// 必傳,且爲 String 類型
propC: {
type: String,
required: true
},
// Number 類型的默認值
propD: {
type: Number,
default: 100
},
// 對(duì)象類型的默認值
propE: {
type: Object,
// 對(duì)象或者數組應當用(yòng)工(gōng)廠(chǎng)函數返回。
// 工(gōng)廠(chǎng)函數會(huì)收到(dào)組件所接收的原始 props
// 作(zuò)爲參數
default(rawProps) {
return { message: 'hello' }
}
},
// 自(zì)定義類型校驗函數
propF: {
validator(value) {
// The value must match one of these strings
return ['success', 'warning', 'danger'].includes(value)
}
},
// 函數類型的默認值
propG: {
type: Function,
// 不像對(duì)象或數組的默認,這(zhè)不是一個
// 工(gōng)廠(chǎng)函數。這(zhè)會(huì)是一個用(yòng)來(lái)作(zuò)爲默認值的函數
default() {
return 'Default function'
}
}
}
}
一些(xiē)補充細節:
所有 prop 默認都是可選的,除非聲明(míng)了(le) required: true。
除 Boolean 外(wài)的未傳遞的可選 prop 将會(huì)有一個默認值 undefined。
Boolean 類型的未傳遞 prop 将被轉換爲 false。這(zhè)可以通過爲它設置 default 來(lái)更改——例如:設置爲 default: undefined 将與非布爾類型的 prop 的行爲保持一緻。
如果聲明(míng)了(le) default 值,那麽在 prop 的值被解析爲 undefined 時(shí),無論 prop 是未被傳遞還是顯式指明(míng)的 undefined,都會(huì)改爲 default 值。
當 prop 的校驗失敗後,Vue 會(huì)抛出一個控制台警告 (在開(kāi)發模式下(xià))。
注意
注意 prop 的校驗是在組件實例被創建之前,所以實例的屬性 (比如 data、computed 等) 将在 default 或 validator 函數中不可用(yòng)。
運行時(shí)類型檢查
校驗選項中的 type 可以是下(xià)列這(zhè)些(xiē)原生構造函數:
String
Number
Boolean
Array
Object
Date
Function
Symbol
另外(wài),type 也(yě)可以是自(zì)定義的類或構造函數,Vue 将會(huì)通過 instanceof 來(lái)檢查類型是否匹配。例如下(xià)面這(zhè)個類:
js
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
}
你(nǐ)可以将其作(zuò)爲一個 prop 的類型:
js
export default {
props: {
author: Person
}
}
Vue 會(huì)通過 instanceof Person 來(lái)校驗 author prop 的值是否是 Person 類的一個實例。
Boolean 類型轉換
爲了(le)更貼近原生 boolean attributes 的行爲,聲明(míng)爲 Boolean 類型的 props 有特别的類型轉換規則。以帶有如下(xià)聲明(míng)的 <MyComponent> 組件爲例:
js
export default {
props: {
disabled: Boolean
}
}
該組件可以被這(zhè)樣使用(yòng):
template
<!-- 等同于傳入 :disabled="true" -->
<MyComponent disabled />
<!-- 等同于傳入 :disabled="false" -->
<MyComponent />
當一個 prop 被聲明(míng)爲允許多種類型時(shí),例如:
js
export default {
props: {
disabled: [Boolean, Number]
}
}
無論聲明(míng)類型的順序如何,Boolean 類型的特殊轉換規則都會(huì)被應用(yòng)。
網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發