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原生组件一样,不需要关系根元素是什么元素