内容提要:
- Prop的大小写与类型
- 传递动态和静态的Props
- 单向数据流
- Prop的验证
- 非Prop属性
这页假设你已经读了Components Basics,如果你不了解组件首先读它。
Prop大小写(cameCase vs kebab-case)
HTML属性名是大小写不敏感的,所以浏览器将解释任何大小字符作为小写字母。那意味着当你在DOM模板里使用的时候,camelCased(驼峰命名法) prop 名字会用它的等价物kebab-cased(以连字符分隔):
Vue.component('blog-post',{
// cameCase in JavaScript
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- kebab-case in HTML -->
<blog-post post-title="hello"!></blog-post>
此外,如果你使用字符串模板,这个限制不适用。
Prop 类型
到目前为止,我们仅仅看到props 被列作为字符串的数组:
props:['title','likes','isPublished','commentIds','author']
通常,你想要每一个prop具有一个特定的值类型,在这些例子中,你能列出props作为一个对象,属性的名字和值分别包含prop名字和类型:
props:{
title: String,
likes: Number,
isPulished: Boolean,
commentIds: Array,
author: Object
}
这不仅可以记录你的组件,而且如果你传错了类型也可以在浏览器的JavaScript 控制台警告用户,你能学到更多关于类型检查和其他prop校验在本页的后面type checks and other prop validations 。
传递静态或动态Props
到目前为止,你已经知道props传递一个静态值,像这样:
<blog-post title="My journey with Vue"></blog-post>
你也知道props用`v-bind动态赋值,像这样:
<!-- Dynamically assgin the value of a variable -->
<blog-post v-bind:title="post.title"></blog-post>
<!-- 动态分配一个复杂表达式的值 -->
<blog-post v-bind:title="post.title + ' by ' + post.author.name">
在上面的两个例子里,我们碰巧传递了字符串的值,但任何类型的值实际上都能传递给prop.
传递一个Number
<!-- 即使‘42’是一个静态的,我们需要 v-bind 去告诉Vue 这是一个JavaScript表达式而不是一个字符串 -->
<blog-post v-bind:likes="42"></blog-post>
传递一个布尔值
<!-- 包含无值的prop意味着‘true’ -->
<blog-post is-published></blog-post>
<!-- 虽然‘false’是静态的,我们需要v-bind告诉Vue,这是一个JavaScript表达式,而非一个字符串 -->
<blog-post v-bind:is-pubiished="false"></blog-post>
<!-- 动态分配一个变量的值 -->
<blog-post v-bind:is-published="post.isPublished"></blog-post>
传递一个数组
<!-- 虽然数组是静态的,我们需要v-bind告诉Vue -->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<!-- 动态的分配变量的值 -->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>
传递一个对象
<!-- 虽然对象是静态的,我们需要v-bind 告诉Vue 这是一个JavaScript表达式而不是一个字符串-->
<blog-post v-bind:author="{name: 'Veronica', company: 'Veridian Dynamics'}"></blog-post>
<!-- 动态分配一个变量的值 -->
<blog-post v-bind:author="post.author"></blog-post>
传递一个对象的属性
如果你想传递一个对象的所有属性作为一个props,你可以使用v-bind
不携带参数(v-bind
代替 v-bind:prop-name
)例如,给一个post
对象:
post:{
id: 1,
title: 'My Journey with Vue'
}
以下模板:
<blog-post v-bind="post"></blog-post>
等价于
<blog-post v-bind:id="post.id"
v-bind:title="post.title">
</blog-post>
单向数据流
所有props表单在子属性和父节点形成一个单向向下绑定:当父属性更新的时候,它将流向子节点。但是反过来则不行。这样是为了阻止子节点意外的改变父节点的状态,造成你的应用数据流难于理解。
此外,每一次父组件被更新,所有在子组件的props都会被用最新的值刷新。这意味着你不应该在子组件内部改变一个prop,如果你这样做了,Vue将在控制台警告你。
这里有两个例子:试图去改变一个prop:
-
prop被用于传递一个初始值,子组件想要以后用它作为一个本地数据属性。在这个例子里,最好用于去定义一个本地数据属性去使用prop作为初始值:
props:['initialCounter'] data: function: () { return { counter:this.initialCounter } }
-
prop 被传递作为一个未处理的需要被转化的值。在这个例子里,最好定义一个计算属性用于prop’s的值:
props:['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
注意:对象和数组在JavaScript中通过引用被传递,所以如果prop是一个数组或对象,在子组件改变对象或数组本身将影响父组件的状态。
Prop 验证
组件可能指定条件对于props,如你所看到的类型。如果一个条件没有满足要求,Vue将会在浏览器的JavaScript后台给你警告。这在开发供别人使用的组件时尤其有用。
对于特定的prop校验,你能提供一个校验条件的对象给到props的值。代替一个数组字符串,例如:
Vue.component('my-component',{
props:{
// 基本类型检查(‘null’匹配任何类型)
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) {
// The value must match one of these strings
return ['success','warning','danger'].indexOf(value) !== -1
}
}
}
})
当prop验证失败,Vue将产生一个后台警告(如果使用开发环境构建)
注意:props被验证需要在一个组件实例被创建之前,所以实例属性(e.g.
data
,computed
, etc)将不可用在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
的值是否使用new Person
创建的。
非Prop 属性
一个非prop属性也是用于传递该组件的一个属性,但是没有相应的prop定义。
而显示的定义props更适合传递信息给子组件,组件库的作者不能总是预见组件总是被使用的上下文。这也是组件为什么能接受任意属性的原因。这就是为什么组件能接受任何属性被添加到组件的根元素的原因。
例如,假设我们使用一个第三方Bootstrap插件上的bootstrap-date-input
,它需要一个input
的data-date-picker
属性。我们能增加这个属性给我们的组件实例:
<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>
date-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
被定义了两个不同的值。
form-control
通过组件在它的模板中设的值date-picker-theme-dark
,通过它的父视图传递给组件
对于大部分属性,值被提供给组件将替换组件设置的值,例如这里,传递type=“text”
将替换type=“date”
并且破坏它,庆幸的是,class
和style
属性更智能一点,他们的值被合并了,组成最后的值:form-control date-picker-theme-dark
。
禁用属性继承
如果你不希望组件的根元素去继承属性,你能在组件的操作项里设置inheritAttrs:false
,例如:
Vue.component('my-component',{
inheritAttrs: false,
})
这在与$attrs
实例属性一起使用的时候特别有用,该属性包含属性的名字和值被传递给组件,例如:
{
class: 'username-input',
placeholder: 'Enter your username'
}
使用 inheritAttrs:false
和 $attrs,
你可以手动决定将属性转给哪一个元素,通常用基本组件base components描述:
Vue.component('base-input',{
inheritAttrs: false,
props: ['label','value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input',$event.target.value)">
</label>
`
})
该模式允许你想使用原生HTML元素那样使用基本组件,而不用担心哪个元素是真正的根元素:
<base-input
v-model="username"
class="username-input"
placeholder="Enter your username ">
</base-input>