组件之间的通讯
# 组件之间的通讯
Vue组件之间的通讯有多种方法:①父组件给子组件传值。②子组件给父组件传值。③兄弟组件之间的传值。组件之间的通讯在实际开发中可增加代码的重用性和扩展性。
# 父组件给子组件传值
组件是当作自定义元素来使用的,HTML元素有属性,同样,组件也可以有属性,利用属性给子组件内部传值,子组件使用props来接收。代码如下:
//子组件
let ChildrenComponent={
//使用props接收属性
props:["post-title","sub-title"],
template:`
<div>{{postTitle}}-{{subTitle}}</div>
`
};
//父组件
let ParentComponent={
data(){
return {
title:"我是父组件的title",
subTitle:"我是父组件的subTitle"
}
},
template: `
<div>
<ChildrenComponent :post-title="title" :sub-title="subTitle"></ChildrenComponent>
</div>
`,
components:{
ChildrenComponent
}
};
new Vue({
el:"#app",
components:{
ParentComponent
},
template:`
<div>
<ParentComponent></ParentComponent>
</div>
`
})
注意:接收的属性名是kebab-case(短横线分隔命名)来使用,在Mustache标签里面变量名要用camelCase(驼峰命名)来使用,因为Mustache标签不支持kebab-case。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Vue还支持属性类型的验证,比如子组件接收的属性值应该是一个对象类型,结果父组件传的是一个字符串类型的值,这显然不符合要求,这时需要属性验证。代码示例如下:
//使用props接收属性并验证类型
props:{
"post-title":{
type:String
},
"sub-title":{
type:String
}
},
2
3
4
5
6
7
8
9
10
验证的type值可以是下列原生构造函数中的一个:
- lString
- lNumber
- lBoolean
- lArray
- lObject
- lDate
- lFunction
- lSymbol
在实际开发中推荐使用验证属性的方式接收prop。
验证属性的方式还支持,父组件传过来的属性是否为必有属性,代码如下:
props:{
"post-title":{
type:String,
required:true //父组件必须传入此属性
}
},
2
3
4
5
6
验证属性的方式还支持默认值,在组件没有传入属性的时候,可以给一个默认值,代码如下:
//使用props接收属性并验证类型
props:{
"post-title":{
type:String,
default:"我是post-title默认值"
}
},
2
3
4
5
6
7
8
如果是Array或Object类型默认值需要用工厂函数返回,代码如下:
props:{
"list":{
type:Array,
default:()=>[] //工厂函数返回默认值
}
},
2
3
4
5
6
7
组件也可以接收任意的属性,比如给组件添加class或style属性等,而这些外部设置的属性会被添加到这个组件的跟元素上面。代码如下:
//子组件
let InputComponent={
template:`
<input type="text" class=" input" />
`
};
//父组件
let ParentComponent={
template: `
<div>
<InputComponent class="my-input"></InputComponent>
</div>
`,
components:{
InputComponent
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
而对于其他属性而言,则会覆盖,代码如下:
//父组件
<InputComponent class="my-input" type="checkbox" checked></InputComponent>
在<InputComponent>组件上面添加属性type和checked,InputComponent组件内部根元素input存在属性type则覆盖,最终type的值为checkbox,checked属性不存在,则添加checked属性。
2
3
4
5
如果不希望根组件继承外部设置的属性,可以在子组件的选项中设置属性inheritAttrs的值为false,代码如下:
//子组件
let InputComponent={
template:`
<input type="text" class="input" />
`,
inheritAttrs:false//根元素不继承外部设置的属性
};
2
3
4
5
6
7
8
由于prop传递数据属于单向数据流,父组件的属性变化会向下传递给子组件,但是反过来却不行,这可以防止子组件意外改变父组件的状态,从而导致应用程序的数据流难以理解。每次父组件更新数据时,子组件的prop都会刷新为最新的值。这意味着我们不应该在组件内部直接更改prop,如果更改Vue会在浏览器的控制台中给出警告。
可以使用本地的data方法或是引用类型来解决。
# 子组件给父组件传值
在Vue中是通过自定义事件来实现的,子组件使用$emit()方法触发事件,父组件使用v-on指令监听子组件的自定义事件来完成通讯。
$emit()
方法的语法形式如下:
vue.$emit(eventName,[...args])
eventName
是自定义事件名称,args
是附加参数
# 兄弟组件之间传值
在实际开发中也会出现兄弟组件(非父子组件)之间传值的需求,实现的方式很简单,声明一个bus变量其值为new Vue(),然后在A组件bus.$emit()方法传值,B组件用bus.$on方法接收A组件传过来的值,来完成兄弟组件之间的传值。
# 父组件与子组件实现双向绑定
在开发UI库时都是对HTML表单控件进行封装的,比如自定义了一个input组件,在自定义的input组件上面添加v-model指令,默认v-model指令是不生效的,这时我们要手动让它支持v-model指令,常用的解决方案有两种:
第一种使用computed解决,第二种使用model解决。
# 父组件调用子组件的方法
在实际开发中经常会遇到父组件调用子组件的方法,其实很简单,通过ref就可以直接调用子组件里面的方法