🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# `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> ~~~ 再说一遍,如果你使用字符串模板,这些限制都不会生效。