父子组件间通信
vue
提供了prop
实现父组件向子组件传递数据,提供emit
实现子组件向父组件回传数据。
组件参数传递 prop
【组件创建使用示例】
在该示例的HelloWorld
组件中我们接收了msg
数据,然后在使用组件时可以传入指定的msg
数据。
// 定义组件
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
};
</script>
// 使用组件
<HelloWorld
ref="helloWorld1"
msg="第二个 HelloWorld"
@on-msg-click="onMsgClick"
/>
下面是使用prop
时的可选的一些参数,推荐在写prop
是将信息描述完整。如:是否必填,是否有默认值等
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 (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
prop
里面的type
可以传递那些类型的数据呢?
String
Number
Boolean
Array
Object
Date
Function
Symbol
- 额外的,它还可以是一个自定义的构造函数,并且通过
instanceof
来进行检查确认。
所有的 prop
都使得其父子 prop
之间形成了一个单向下行绑定:父级prop
的更新会向下流动到子组件中,但是反过来则不推荐。因为这样会使得子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
重要PS:
比如在
子组件更新了父组件里的对象属性,从而导致页面显示效果不一致
。故推荐在更新子组件数据时必须从父组件去更新
额外的,每次父级组件发生变更时,子组件中所有的prop
都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变prop
。如果你这样做了,Vue
会在浏览器的控制台中发出警告。
子组件需要更新数据如何处理
前面我们也推荐了必须从父组件去更新子组件的数据,但是有的时候业务很变态,需要在子组件里面修改
prop
的数据,我们该如何做呢?
我们可以在computed
函数里面定义内部的数据接收prop
传递过来的值,然后改变的就是该组件computed
内部定义的值即可。伪代码如下:
<template>
<div class="hello">
<h2>counter: {{ counter }}</h2>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
initialCounter: {
type: Number,
default: 0,
},
},
computed: {
counter() {
return this.initialCounter;
},
}
};
</script>
我们传入的是initialCounter
,然后赋值给计算属性的counter
字段,后续在组件中即可使用counter
做修改。
有时候我们需要从子组件传递数据给父组件,那么可以通过emit
事件来实现。
监听子组件事件 emit
组件创建使用示例
示例中我们通过点击子组件中的msg
信息传递数据给父组件,并在console
中打印结果。
伪代码示例如下:
在子组件定义处理点击事件,然后通过$emit
将数据发送给父组件
<template>
<div class="hello">
<h1 @click="handleData">{{ msg }}</h1>
</div>
</template>
methods: {
handleData() {
this.$emit("on-msg-click", "点击msg传递的数据");
},
},
父组件中接收并处理的代码如下:
<HelloWorld
ref="helloWorld1"
msg="第二个 HelloWorld"
@on-msg-click="onMsgClick"
/>
methods: {
onMsgClick(msg) {
console.log(msg);
},
},
官方推荐我们在this.$emit(‘事件名’,数据)
的事件名始终使用 kebab-case
格式。
我们已经知道父子组件间如何通信,但是很多时候我们需要在多个组件以及没有父子关系的组件间通信,官方及社区提供了很多的解决方案。比如EventBus
和Vuex
.
多层级组件间通信
如果我们使用vue
提供的prop
和emit
实现会很麻烦,需要层层嵌套。下篇文章介绍EventBus
和Vuex
两种方式实现。