做自(zì)由與創造的先行者

Props

Vue.js中文(wén)手冊

此章節假設你(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)發
下(xià)一篇:組件事(shì)件
上(shàng)一篇:組件注冊