Vue父子组件的通信
一 父组件向子组件通过props传递数据
在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称。
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
Prop 是你可以在组件上注册的一些自定义 attribute。
当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。
1. props值为数组时候
为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop列表中:
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问data
中的值一样。
一个 prop 被注册之后,你就可以像这样把数据作为一个自定义 attribute 传递进来,在这里我们直接用k-v对显示了值,而没有进行v-bind的动态绑定(下面有介绍):
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
然而在一个典型的应用中,你可能在 data 里有一个博文的数组:
new Vue({
el: '#blog-post-demo',
data: {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
]
}
})
并想要为每篇博文渲染一个组件:
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
></blog-post>
如上所示,你会发现我们可以使用 v-bind
来动态传递 prop。这在我们一开始不清楚要渲染的具体内容,比如从一个 API 获取博文列表的时候,是非常有用的。
2. props值为对象时候
通常我们希望每个 prop 都有指定的值类型。这时,我们可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
3. 关于props值为对象时候,我们可以对传入的数据做校验或者说验证
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
3.1.在props中我们可以传一个值做一个对象元素传入,对其做三个限定.如下如代码中的name
- type 约定该元素类型
- default 约定默认值(如果父组件不传入值的话将直接使用默认值)
- required 约定是否要求必须传入(如果要求了父组件没有传入则会报错)
props: {
title:String,
propB: [String, Number],
name:{
type:String,
default:"zyh",
required:true
}
}
3.2 我们可以对传入的值约定多个可能类型
如propB: [String, Number]
3.如果我们要求传入的数据为对象或者数组,那么默认值需要用工厂函数获取
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
}
二 子传父---通过监听子组件事件传递数据和信号给父组件
不同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。
举个例子,如果触发一个 camelCase 名字为的事件:this.$emit('myEvent')
则监听这个名字的 kebab-case 版本是不会有任何效果的:
<my-component v-on:my-event="doSomething"></my-component>
不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或 property 名,所以就没有理由使用 camelCase 或 PascalCase 了。
并且v-on
事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent
将会变成 v-on:myevent
——导致 myEvent
不可能被监听到。
因此,Vue官方推荐始终使用 kebab-case 的。
自定义事件的流程:
- 在子组件中,通过$emit来触发事件。
- 在父组件中,通过v-on来监听子组件事件。 一个传递加减信号的demo
自定义组件的 v-model
一个组件上的 v-model
默认会利用名为 value
的 prop 和名为 input
的事件,但是像单选框、复选框等类型的输入控件可能会将 value
attribute 用于不同的目的。model
选项可以用来避免这样的冲突:
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
现在在这个组件上使用 v-model 的时候:
<base-checkbox v-model="lovingVue"></base-checkbox>
这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox>触发一个 change
事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。
注意你仍然需要在组件的 props 选项里声明 checked 这个 prop。
关于子组件向父组件传参数量问题
$emit传递一个参数时
子组件:
this.$emit('closeChange',false);
父组件:
<posilCom @closeChange="closeCom($event)"></posilCom>
closeCom(msg) {
this.msg = msg;
}
$emit传递多个参数时
子组件:
this.$emit('closeChange',false,true);
父组件:
<posilCom @closeChange="closeCom(arguments)"></posilCom>
closeCom(msg) {
this.msg1 = msg[0];
this.msg2 = msg[1];
}