Prop就是在組件上自定義的特性
官方文檔
基本使用方式
子組件:PropDemo.vue
<template>
<div>
<p>{{myMsg}}</p>
</div>
</template>
<script>
export default {
name: "PropDemo",
props: {
myMsg: {
type: String,
// 默認值,沒有傳入msg時使用
default: 'hi prop'
}
}
}
</script>
父組件
<template>
<div>
<prop-demo :my-msg="message" />
</div>
</template>
<script>
import PropDemo from '@/components/PropDemo'
export default {
name: "home",
components: {
PropDemo
},
data: () => ({
message: 'hi vue.js'
})
}
</script>
標題Prop類型
props: {
myMsg: {
type: String,//字符串
// 默認值,沒有傳入msg時使用
default: 'hi prop'
},
count: Number,//數字
isVueAwesome: Boolean,//布爾
ids: Array,//數組
author: Object,//對象
callback: Function//函數
}
除了上述的類型外,還可以通過構造函數自定義一個類型
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
props: {
author: Person
}
單向數據流
所有的prop都是由父組件綁定到子組件,父組件更新prop,子組件會馬上刷新數據;
子組件不應該修改prop,否則會改變父組件中的數據,導致數據流變得混亂,難以理解。
如果子組件中需要修改prop,vue推薦了兩種方式
-
在子組件的data中定義一個屬性,將需要修改的prop用作其初始值
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } }
-
使用prop作爲初始值定義一個計算屬性
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
單向數據流反面例子(下面的代碼是不推薦的)
子組件
<template>
<div>
<p>{{author.name}} is {{author.feature}}</p>
</div>
</template>
<script>
export default {
name: "PropDemo",
props: {
author: {
type: Object,//對象
default: function () {
return {
name: 'vue',
feature: 'awesome'
}
}
}
},
mounted() {
//子組件中更新prop數據,會導致父組件中的數據發生無法預料的結果
this.author.name = 'vuejs'
}
}
</script>
父組件
<template>
<div>
//由於子組件修改的prop,這裏並不會按照預期出現vue
<p>{{author.name}}</p>
<prop-demo :author="author" />
</div>
</template>
<script>
import PropDemo from '@/components/PropDemo'
export default {
name: "home",
components: {
PropDemo
},
data: () => ({
author: {
name: 'vue',
feature: 'Powerful'
}
})
}
</script>
標題Prop 驗證
建議每一個prop都添加預期的條件
比如已經知道一個prop是一個布爾類型的屬性,就應該通過下面方式添加類型
props: {
isVueAwesome: Boolean
}
或者
props: {
isVueAwesome: {
type: Boolean
}
}
更多的需求驗證方式
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
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 ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
當 prop 驗證失敗的時候,(開發環境構建版本的) Vue 將會產生一個控制檯的警告。
非prop的特性
非prop特性指的就是使用子組件的時候傳入一個屬性,但是子組件內部並沒有定義這個屬性
替換和合並
下面這段代碼中prop-demo標籤中的class和style是最常見的屬性,但是prop-demo組件中並沒有定義這兩個prop,所以他們就屬於非prop的特性
<template>
<div>
<prop-demo class="color-red" style="font-size: 20px" />
</div>
</template>
雖然沒有定義class和style屬性,但是vue並不會拋棄他們,而是將他們加到這個組件的根元素上,與根元素的樣式合併使用
但是並不是所有的非prop屬性都會合並
假如prop-demo的模板根元素是input,定義了屬性type爲number
<template>
<input type="number" />
</template>
而父組件中也傳入了一個type爲date,這是傳入的type會替換掉子組件中的type,所以input的最終類型爲date
<template>
<div>
<prop-demo type="date" />
</div>
</template>
禁用特性繼承
可以通過下面方式禁用根元素繼承特性(class和style除外)
<script>
export default {
inheritAttrs: false,//禁用根元素繼承特性
name: "PropDemo"
}
</script>
禁用根元素繼承特性更多的是和$attrs配合使用
$attrs可以選擇子控件中的那個元素來繼承父組件傳入的特性(class和style除外)
父組件
<template>
<div>
<prop-demo placeholder='Enter your age'/>
</div>
</template>
子元素
<template>
<div>
<input type='number' v-bind='$attrs' />
</div>
</template>
子元素的根元素爲div,顯然它不需要placeholder這個屬性,而input需要
只需要在input標籤中添加v-bind="$attrs"即可
在使用子組件的時候可以想html原生組件一樣,不需要關係根元素是什麼元素