文章目录
Prop的大小写
HTML中的attribute(属性)名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符,这样也就意味着aaBb(驼峰命名法)的prop名 等价于 aa-bb(短横线分隔命名)命名:
因此,在Vue2中,会约定(也算个人写法),使用class类名时,直接使用短横线分隔命名;而在使用函数命名时使用驼峰命名法,这样后期维护找相应的代码也好找
Vue.component('blog-post', {
// 在js中最好使用 驼峰命名法
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在HTML中 使用 短横线命名法 -->
<blog-post post-title="hello"></blog-post>
如果使用的是 字符串模板,那么这个限制就不存在了
Prop类型
我们只看到以字符串数组形式列出的prop:
props: ['title', 'content', 'author']
这时,我们就可以以对象形式列出prop,这些property的名称和值分别是prop各自的名称和类型:
props: {
title: String,
links: Number,
isOver: Boolean,
todoLists: Array,
author: Object,
callBack: Function,
contactsPromise: Promise
}
这样对面传来不同类型的值,prop也会进行类型检查
传递静态或动态Prop
给prop传入一个静态的值:
<blog-post title="this is a title"></blog-post>
当然,我们也知道如何通过v-bind / :
来动态赋值:
<!-- 动态赋予一个变量的值 -->
<blog-post :title="post.title"></blog-post>
<!-- 动态赋予一个比之前复杂的值,这个时候更喜欢 模板字符串 -->
<blog-post :title="`${post.title} by ${post.name}`"></blog-post>
上面两个例子中,传入的值都是字符串类型,但实际上任何类型我们都可以传递给prop,接下去慢慢看
传入一个数字
<!-- 即便是一个42是静态的,但是我们仍然需要使用 v-bind 来告诉Vue -->
<!-- 这是一个js表达式,而不是字符串 -->
<blog-post :number="42"></blog-post>
<!-- 最常见的便是使用变量 来进行动态赋值 -->
<blog-post :number="post.number"></blog-post>
传入一个布尔值
<!-- 包含prop没有值的情况在内,都意味着 true,比如于elemeneUI的属性 -->
<blog-post is-over></blog-post>
<!-- 这是一个js表达式 -->
<blog-post :is-over="false"></blog-post>
<!-- 用一个变量来赋值 -->
<blog-post :is-over="post.isOver"></blog-post>
传入一个数组
<!-- 这是一个js表达式 -->
<blog-post :comment="[24, 65, 85]"></blog-post>
<!-- 用一个变量来动态控制 -->
<blog-post :comment="post.commentList"></blog-post>
传入一个对象
<!-- 这是一个js表达式 -->
<blog-post
:author="{
name: 'post.name',
age: 'post.name'
}">
</blog-post>
<!-- 用一个变量来控制 -->
<blog-post :author="post.author"></blog-post>
传入一个对象的所有property
如果想要将一个的对象的所有property都作为prop传入,可以使用不带参数的 v-bind
(取代 v-bind: prop-name
),例如,对于一个给定的对象post:
post: {
id: 123,
title: 'this is a title'
}
模板为:
<blog-post v-bind="post"></blog-post>
<!-- 等价于 -->
<blog-post
:id="post.id"
:title="post.title"
></blog-post>
单向数据流
所有的prop都使得父子prop之间形成了单向下行绑定:父级prop的更新会向下流动到子组件中,但是发过来就不行。这样会防止从子组件意外变更父级组件的状态,从而导致自己的数据流向难以理解。
看完prop,可以尝试看看 sync修饰符的原理和作用(Vue高级)
还有,每次父级组件数据省变更时,子组件中所有的prop都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变prop,这样做,Vue会在浏览器的控制台中发出警告。
这里有两种常见的试图变更一个prop的情形:(不应该做的)
- 这个prop用来传递一个初始值;这个子组件接下来希望将其作为一个本地的prop数据来使用。在这种情况下,最好定义一个本地的data property 并将这个prop用作其初始值:
props: ['initCiunter'],
data: function() {
return {
counter: this.initCounter
}
}
- 这个prop以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个prop的值来定义一个 计算属性 :
props: ['size'],
computed: {
normalSize: funtion() {
return this.size.trim().toLowerCase()
}
}
*注意:*在js中对象和数组是通过引用传入的,所以对于一个数组或对象类型的prop来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态:
Prop验证
我们在和别人合作(一起写组件)时,为防止对方传来的值类型错误,导致报错,我们都希望每个prop都有指定的值类型。
为了定制prop的验证方式,可以为props中的值提供一个带有验证需求的对象,而不是一个字符串数组:
Vue.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(val) {
// 这个值必须匹配以下字符串中的一个
return ['success', 'warning', 'danger'].includes(val)
}
}
}
}
})
当prop验证失败时,会在开发环境构建版本的 Vue ,产生一个控制台的警告。
*注意:*prop会在组件实例创建之前进行验证,所以实例的property(如data、computed等)在default或validator函数中是不可用的
类型检查
prop中 type
可以是下列原生构造函数中的一个:
String
Number
Boolean
Array
Object
Date
Function
Symbol
还有,type 还可以是一个自定义的构造函数,并且通过 instanceof
来进行检查确认,比如,给定下列现成的构造函数
function Peison(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
// 也可以使用
Vue.component('blog-post', {
props: {
author: Person
}
})
来验证 author
prop的值是否是通过 new Person
创建的
非prop的attribute
一个非prop的attribute是指向一个组件,但是该组件并没有相应的prop定义的attribute。
我们需要组件有什么样的attribute就需要将相应的attribute添加到这个组件的根元素上。
比如,我们现在需要使用Bootstrap插件使用第三方<bootstrap-date-input>
组件,这个插件需要在其<input>
上用到一个data-date-picker
attribute,这时我们就可以将这个 attribute 添加到相应的组件实例上:
<bootstrap-date-picker data-date-picker="activated"></bootstrap-date-picker>
然后这个 data-date-picker="activated"
attribute 就会自动添加到 <bootstrap-date-input>
的根元素上
替换/合并已有的Attribute
如果<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
这是从组件的父级传入的
对于绝大多数attribute来说,从外部提供给组件的值会替换组件内部设置好的值。所以如果传入 type="text"
就会替换掉 type="date"
并把它破坏。
还好,class 和 style attribute会稍微智能些,两边的值会合并起来,从而得到最终的值:
form-control date-picker-theme-dark
禁用Attribute继承
如果不希望组件的根元素继承 attribute,可以在 组件的选项中设置 inheritAttrs: false
:
Vue.component('blog-post', {
inheritAttrs: false,
// ...
})
这十分适合配合 $attrs
property使用,该property包含了传递给一个组件的 attribute 名和 attribute 值:
{
require: true,
placeholder: 'Enter your age'
}
有了 inheritAttrs: false
和 $attrs
,你就可以决定这些attribute会被赋予哪个元素,一般在写 基础组件 的时候是常用到的:
Vue.component('blog-post', {
inheritAttrs: false,
props: ['label', 'value'],
template:`
<label>
{{ label }}
<input
v-bind="$attrs"
:value="value"
@input="$emit('input', $event.target.value)"
>
</label>
`
})
注意:inheritAttrs: false
选项不会影响 style 和 class 的绑定。
这个模式允许你在使用基础组件的时候更像是使用原始的HTML元素,而不会担心哪个元素是真正的根元素:
<base-input
label="UserName:"
v-model="userName"
required
placeholder="请输入你的名字"
></base-input>