# `pros`
>[info]学习本节,你应该已了解过[组件基础](https://www.kancloud.cn/zhouyu629/vue3x/2178193)
## `prop`类型
前面我们讨论过,`props`可以是一个字符列表的数组。
~~~
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
~~~
但是有时候,我们需要传递一些特别的类型数据。这种情况下,我们可以在列表中传递对象,同时传递属性名称和类型即可:
~~~
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // 或其他任何结构
}
~~~
如果类型传递错误,不仅仅只是参考上面的文档自查,同时还会通过浏览器控制台向用户告警。如果想了解类型相关内容,请参考[类型检测和props其它类型验证](https://v3.vuejs.org/guide/component-props.html#prop-validation)。
## 传递静态或动态的`props`
前面传递一个静态`prop`的方法为:
~~~
<blog-post title="My journey with Vue"></blog-post>
~~~
你也可以使用`v-bind`或缩写为`:`来传递动态的`props`:
~~~html
<!-- 静态 -->
<blog-post :title="post.title"></blog-post>
<!-- 动态传递复杂的静态式 -->
<blog-post :title="post.title + ' by ' + post.author.name"></blog-post>
~~~
通过以上两个示例,我们可以传递任何类型数据到`props`。
### **传递数字**
~~~html
<!-- 即使`42`是一个静态数字,我也要动态的告诉Vue -->
<!-- 使用JavaScript表达式比使用字符串更好 -->
<blog-post :likes="42"></blog-post>
<!-- 动态付值. -->
<blog-post :likes="post.likes"></blog-post>
~~~
### **传递布尔值**
~~~html
<!-- 空值为`true`. -->
<blog-post is-published></blog-post>
<!-- 即使`false`是静态值,也要`v-bind` -->
<!-- 使用JavaScript表达式比使用字符串更好 -->
<blog-post :is-published="false"></blog-post>
<!-- 动态传值. -->
<blog-post :is-published="post.isPublished"></blog-post>
~~~
### **传数组**
~~~html
<!-- 静态值也`v-bind` -->
<!-- js表达式比字符串好. -->
<blog-post :comment-ids="[234, 266, 273]"></blog-post>
<!-- 动态 -->
<blog-post :comment-ids="post.commentIds"></blog-post>
~~~
### **传对象**
如果你想把一个对象的所有属性传给`prop`,你可以使用`v-bind`(可以使用`:`代替)。例如有一个`post`对象:
~~~
post: {
id: 1,
title: 'My Journey with Vue'
}
~~~
模板:
~~~html
<blog-post v-bind="post"></blog-post>
~~~
与下面效果一致
~~~html
<blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>
~~~
### **单向数据流**
所有的`props`是父子组件间的**单向绑定**:当父组件属性更新时会传递给子组件,但反之却不行。这会阻止子组件意外的更改父容器的状态,会导致你的应用数据流难以理解。
另外,每次父组件更新时,所有子组件的`props`都会同步刷新。这意味着你不要在子组件中更改`prop`属性的值。如果你这样做了,Vue会在控制台告警。
有两种情形会尝试转变`prop`:
1.**`prop`传递一个初始值,然后子组件希望当成一个局部变量来使用**。这种情部最后再定义一个局部变量并用`prop`赋值。
~~~
props: ['initialCounter'],
data() {
return {
counter: this.initialCounter //这个局部变量只在这个子组件实例内有效
}
}
~~~
2. **`prop`传递的是一个原始数据,需要进行转换才能使用**。这种情况下最好用计算属性为转换`prop`:
~~~
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
~~~
>[info]提示
>注意如果JavaScript的对象和数组类型是关联起来的,子组件更改这两种类型数据,会影响到父组件的状态。
## `prop`验证
组件`prop`有专门的需求关系,如前面提到的数据类型。如果需求不满足,Vue就会通过浏览器控制台告警。这对组件计划给其他人使用时尤其有用。
`props`的验证,你可以提供一个含有需求验证的对象,来替代数组或字符串:
~~~
app.component('my-component', {
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
}
},
// 有默认值的函数
propG: {
type: Function,
// 不像对象或数组的默认值, 这不是工厂函数 - 这是一个用着默认值的函数
default: function() {
return 'Default function'
}
}
}
})
~~~
当`prop`验证失败时,Vue会发送一个控制台告警(如果使用开发模式构建)
>[info]提示
>注意`prop`会在组件创建之前进行验证,所以实例属性(如`data`,`computed`等)在`default`或`validator`函数内部都不可用
### **类型检测**
类型可以是以下原生结构:
* String
* Number
* Boolean
* Array
* Object
* Date
* Function
* Symbol
另外,类型可以是一个自定义构造函数且通过`instanceof`进行检查确认。例如下面的构造函数:
~~~
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
~~~
你可以这样使用:
~~~
app.component('blog-post', {
props: {
author: Person
}
})
~~~
可以通过`new Person`来验证`author`参数。
## `prop`大写小(短横线 VS 驼峰)
HTML标签大小写不敏感,所以浏览器会所有的大写字母理解为小写。这意味着你使用驼峰定义的`prop`在模板内使用时应该用短横线分隔,是等效的:
~~~
const app = Vue.createApp({})
app.component('blog-post', {
// camelCase in JavaScript
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
~~~
~~~html
<!-- HTML中使用短横线分隔 -->
<blog-post post-title="hello!"></blog-post>
~~~
再说一遍,如果你使用字符串模板,这些限制都不会生效。