Prop:
向子组件传递数据,在组件上注册的自定义特性
当值传递给 prop 特性的时候,Prop就变成组件实例的属性
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
});
/* 在父组件传递 props */
<div>
<blog-post title="My journey with Vue"></blog-post>
</div>
通过事件向父级组件发送消息:
调用 $emit() 方法向父级组件触发事件
$emit() 第一个参数为事件名,第二个参数为传入的参数
/* 子组件:通过 $emit('enlarge', arg ) 派发事件 */
<button @:click="$emit('enlarge', 0 )">Enlarge text</button>
/* 父组件: 通过 v-on监听子组件发布的事件和传入的参数 */
<blog-post @:enlarge="getDate"></blog-post>
methods: {
getDate( arg ) { /* 监听的回调接收的参数 */
1 + arg
}
}
============================ 深入 Prop ============================
Prop 的大小写 (camelCase vs kebab-case):
在 JS 中是 camelCase;
在 HTML 中是 kebab-case
/* 在JS中是camelCase */
Vue.component('blog-post', {
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
});
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
传递静态或动态 Prop: 任何类型的值都可以传给一个 prop
/* 静态传递 Prop */
<blog-post title="My journey with Vue"></blog-post>
/* 动态传递Prop */
<blog-post :title="post.title"></blog-post>
/* 动态传递表达式的值 */
<blog-post :title="post.title + ' by ' + post.author.name"></blog-post>
传入一个数字
/* v-bind 告诉 Vue 这是 JS 表达式 */
<blog-post :likes="42"></blog-post>
/* 用变量动态赋值 */
<blog-post :likes="post.likes"></blog-post>
传入一个布尔值
/* prop 没有值的情况下,默认为 true */
<blog-post is-published></blog-post>
/* false 是静态的仍然要 v-bind 告诉 Vue 这是 JS 表达式 */
<blog-post :is-published="false"></blog-post>
/* 用变量动态赋值 */
<blog-post v-bind:is-published="post.isPublished"></blog-post>
传入一个数组
/* 即便数组是静态的,仍要 `v-bind` 告诉 Vue 这是一个 JS 表达式 */
<blog-post :comment-ids="[234, 266, 273]"></blog-post>
/* 用变量行动态赋值 */
<blog-post :comment-ids="post.commentIds"></blog-post>
传入一个对象
/* 即便对象是静态的仍要 v-bind 告诉 Vue 这是一个 JS 表达式 */
<blog-post :author="{ name: 'Veronica', company: 'Dynamics' }"></blog-post>
/* 用变量行动态赋值 */
<blog-post :author="post.author"></blog-post>
传入一个对象的所有属性: 将对象的所有属性都作为 prop 传入,使用不带参数的 v-bind
post: { id: 1, title: 'My Vue' }
<blog-post v-bind="post"></blog-post>
单向数据流
1、父子 prop 之间形成了一个单向下行绑定,父级 prop 的更新会向下流动到子组件中,但是反过来则不行,防止子组件意外改变父级组件的状态,导致数据流向难以理解
2、每次父级组件更新时,子组件中所有的 prop 都将会刷新为最新的值
3、对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态
定义一个本地的 data 属性并将这个 prop 用作其初始值
props: ['initialCounter'],
data() {
return {
counter: this.initialCounter /* 拷贝一个 props 副本 */
}
}
使用 prop 的值来定义一个计算属性
props: ['size'],
computed: {
normalizedSize() {
/* 字符串操作时,new String() 会返回一个新的值, 这样并不会改变传递的 Prop */
return this.size.trim().toLowerCase()
}
}
PropType:类型检查
type 可以是原生JS中类型的任意一种, 也可以是一个自定义的构造函数,通过 instanceof 来进行检查确认
String Number Boolean
Array Object Date
Function Symbol
/* type可以是一个自定义的构造函数 */
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
Vue.component('blog-post', {
props: {
author: Person
}
})
Prop 验证: 指定验证数据类型
prop 在实例创建之前验证,实例属性 data、computed在 default 或 validator 函数中不可用
Vue.component('my-component', {
props: {
propA: Number, /* 基础的类型检查 (`null` 匹配任何类型) */
propB: [String, Number], /* 多个可能的类型 */
propC: { /* required 必填的字符串 */
type: String,
required: true
},
propD: { /* default 带有默认值的数字 */
type: Number,
default: 100
},
propE: { /* default 带有默认值的对象 */
type: Object,
default: function () { /* 对象或数组默认值必须从工厂函数获取 */
return { message: 'hello' }
}
},
propF: { /* validator 自定义验证函数 */
validator(value) {
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
对象或数组默认值必须从工厂函数获取
propE: { /* default 带有默认值的对象 */
type: Object,
default: function () { /* 对象或数组默认值必须从工厂函数获取 */
return { message: 'hello' }
}
}
非 Prop 的特性: prop 传向一个组件时, 该组件并没有相应 prop 定义的特性
禁用特性继承:
如果不希望组件的根元素继承特性,可以在组件的选项中设置 inheritAttrs: false;适合配合实例的 $attrs 属性
Vue.component('base-input', {
inheritAttrs: false, /* 禁用特性 */
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs" /* 配合 $attrs */
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})