vue進階內容總結--Prop (二)

Prop

Prop的大小寫(camelCase vs kebab-case)

HTML 中的特性名是大小寫不敏感的,所以瀏覽器會把所有大寫字符解釋爲 小寫字符。這意味着當你使用  DOM 的模板時,camelCase(駝峯命名法)的 prop名需要使用其等價的 kebab-case(短橫線分隔命名)命名:

Vue.component('blog-post',{
    // 在JavaScript 中是 camelCase的
    props:['postTitle'],
    template:'<h3> {{ postTitle }} </h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-tittle="hello!"></blog-post>

重申一次,如果你使用字符串模板,那麼這個限制就不存在了。

 

Prop類型

到這裏,我們只看到了以字符串數組形式列出的 prop:

props:['tittle','likes','other']

但是,通常我們都希望每個 prop 都有一個指定的值類型。這時,我們可以以對象形式列出 prop,這些屬性的名稱和值分別是 prop 各自的名稱和類型:

prop:{
    tittle:string,
    likes:Number,
    isPublished:Boolean,
    commentIds:Array,
}

這不僅爲你的組件提供了文檔,還會在它們遇到錯誤的類型時從瀏覽器的 JavaScript 控制檯提示用戶。我們會在這個頁面接下來的部分看到 類型檢查和其他 prop 驗證。

傳遞靜態或動態 Prop

像如下這樣,我們已經知道這樣給 prop 傳入一個靜態的值:

<blog-post tittle="My journey with Vue"></blog-post>

我們都知道 prop 可以通過 v-bind 動態賦值,例如:

<!-- 動態賦予一個變量的值 -->
<blog-post v-bind:tittle="post.tittle"></blog-post>

<!-- 動態賦予一個複雜表達式的值 -->
<blog-post 
v-bind:tittle="post.tittle + ' By ' post.author.name"></blog-post>

在上面的例子中,我們傳入的值都是字符串類型的,但實際上任何類型的值都可以傳給一個 Prop。

 

傳入一個數字

<!-- 即便 `42` 是靜態的,我們仍然需要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串 -->
<blog-post v-bind:likes="42"></blog-post>

<!-- 用一個變量賦值 -->
<blog-post v-bind:likes="post.likes"></blog-post>

 

傳入一個布爾值

<!-- 包含該 Prop 沒有值得情況在內,都意味着 `true` -->
<blog-post is-published></blog-post>


<!-- 即便 `false`是靜態的,我們仍然需要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串 -->
<blog-post v-bind:is-published="false"></blog-post>


<!-- 用一個變量進行動態賦值 -->
<blog-post v-bind:is-published="post.isPublished"></blog-post>

 

傳入一個數組

<!-- 即便數組是靜態的,我們仍然需要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串。 -->
<blog-post v-bind:comment-ids:"[123,234,456]"></blog-post>

<!-- 用一個變量進行動態賦值。 -->
<blog-post v-bind:comment-ids:"post.commentIds"></blog-post>

 

傳入一個對象

<!-- 即便對象是靜態的,我們仍然需要`v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式 而不是一個字符串 -->
<blog-post
v-bind:author="{
    name:'zzk',
    company:'Xnew'
}"></blog-post>


<!-- 用一個變量進行動態賦值 -->
<blog-post v-bind:author="post.author"></blog-post>

 

傳入一個對象的所有屬性

如果你想要將一個對象的所有屬性都作爲 prop 傳入,我們可以使用不帶參數的 v-bind (取代 v-bind:prop-name),例如:對於一個給定的對象 post:

post:{
    id:1,
    tittle:"My Journey with Vue"
}

下面的模板:

<blog-post v-bind:"post"></blog-post>

等價於:

<blog-post
v-bind:id='post.id'
v-bind:tittle='post.tittle'></blog-post>

 

單向數據流

所有的 prop 都使得其父子 prop 之間形成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,但是反過來則不行。這樣會防止從子組件意外改變父級組件的狀態,從而導致你的應用的數據流向難以理解。

 

當然了,額外的,每次父級組件發生更新時,所有子組件的 prop 都會被重新刷新到最新值。這意味着我們不應該在一個子組件內部改變 prop。如果我們這樣做了,Vue 會在瀏覽器的控制檯中發出警告。

 

這裏有2種常見的試圖改變一個 prop 的情形:

1. 這個 prop 用來傳遞一個初始值;這個子組件接下來希望將其作爲一個本地的 prop 數據來使用。在這種情況下,最好定義一個本地的 data 屬性並將這個 prop 用作其初始值:

props:['initialCounter'],
data: function () {
    return {
        counter:this.initialCounter
    }
}

2.這個 prop 以一種原始的值傳入且需要進行轉換。 在這種情況下,最好使用這個 prop 的值來定義一個計算屬性:

props:['size'],
couputed:{
    nomalizedSize:function (){
        return this.size.trim().toLowerCase()
    }
}

注意:在 JavaScript 中對象和數組是通過引用傳入的,所以對於一個數組或對象類型的 prop 來說,在子組件中改變這個對象或數組本身將會影響到父組件的狀態。

 

Prop驗證

我們可以爲組件的 prop 指定驗證要求,例如你知道的這些類型。如果有一個需求沒有被滿足,則 Vue 會在瀏覽器控制檯中警告你。這在開發一個會被別人用到的組件時尤其有幫助。

 

爲了定製 prop 的驗證方式,我們可以爲 props 中的一個值提供一個帶有驗證需求的對象,而不是一個字符串數組。例如:

Vue.component('my-component',{
    props:{
        //基礎的類型檢查('null' 和'underfined' 會通過任何類型驗證)
        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 () {
            //這個值必須匹配下列字符串中的一個
            return ['success','warning','danger'].indexOf(value) !== -1
        }
    }
})

當 prop 驗證失敗的時候,(開發環境構建版本的) Vue將會產生一個控制檯的警告。

 

注意:那些 prop 會在一個組件實例創建之前進行驗證,所以實例的屬性(如data、computed 等)在 default 或 validator 函數中是不可用的。

 

類型檢查

Type 可以是下列原生構造函數中的一個:

String
Number
Boolean
Array
Object
Date
Function
Symbol

額外的, Type 還可以是一個自定義的構造函數,並且通過 instanceof 來進行檢查確認。例如,給定下列現成的構造函數:

function Person (firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
}

我們可以使用以下的方式:

Vue.component('blog-post',{
    props:{
        author:Person
    }
})

來驗證 author prop的值是否是通過 New Person 來創建的。

 

非 Prop 的特性

一個非 Prop 特性是指傳向一個組件,但是該組件並沒有相應 prop 定義的特性。

 

因爲顯示定義的 prop 適用於向一個子組件中傳入信息,然而組件庫的作者並不總能預見組件會被用於怎麼樣的場景。這也是爲什麼組件可以接受任意的特性,而這些特性會被添加到這個組件的根元素上。

 

舉個例子,假如我通過一個 Bootstrap 插件使用了一個第三方的 <bootstrap-date-input> 組件時,這個插件需要在其 <input> 上用到一個 data-date-picker 特性。我們可以將這個特性添加到你的組件實例上:

<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>

 

替換/合併已有的特性

想象一下, <bootstrap-date-input> 的模板時這樣的:

<input type="date" class="form-control">

爲了給我們的日期選擇器插件定製一個主題,我們可能需要像這樣添加一個特別的類名:

<bootstrap-date-input
data-date-picker:"activated"
class="date-picker-theme-dark"></bootstrap-date-input>

在這種情況下,我們定義了兩個不同的 class 的值:

fom-control, 這是在組件的模板內設置好的

date-picker-theme-dark,這是從組件的父級傳入的

 

對於絕大多數特性來說,從外部提供給組件的值會替換掉組件內容設置好的值。所以如果傳入 type="text" 就會替換到 type="date" 並把它破壞掉。不過慶幸的是, class 和 style 特性會稍微智能一些,即兩邊的值會被合併起來,從而得到最終的值:form-control date-pick-theme-dark 。

 

禁用特性繼承

如果我們不希望組件的根元素繼承特性,我們可以在組件的選項中 設置 inheritAttrs:false。例如:

Vue.component('my-component',{
    inheritAttrs:false,
    // 此處省略....
})

這尤其適合配合實例的 $attrs 屬性使用,該屬性包含了傳遞給一個組件的特性名和特性值,例如:

{
    required:true,
placehoder:'Enter your username :'
}

有了 inheritAttrs:false 和 $attrs。我們就可以手動決定這些特性會被賦予哪個元素。在撰寫 基礎組件 的時候是常會被用到的:

Vue.component('base-input',{
    inheriatAttrs:false,
    props:['label','value'],
    template:`
       <label>
           {{ label }}
        <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
      >
       </label>
    `
})

注意: inheritAttrs: false 選項不會影響 style 和 class 的綁定。

 

這個模式允許你在使用基礎組件的時候更像是使用原始的 HTML 元素,而不會擔心哪個元素是真正的根元素:

<base-input
v-model:"username"
required
placeholder="Enter your username">
</base-input>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章