Vue 组件间通信
1. 前言
本小节我们将介绍组件间是如何实现数据通信的。包括父组件向子组件、子组件向父组件、兄弟组件、非关系组件之间的数据通信。组件通信是组件式开发中非常重要的一部分,也是组件式开发中的难点。在学完本小节之后,同学们可以通过反复地编写组件来加深印象。
2. xx解释
组件是 vue 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。我们需要使用特定的方式来实现组件间的数据通信,接下来让我们一个个介绍这几种类别的组件通信是如何实现的。
3. 父组件通过 props 传递数据给子组件
父组件通过 props
属性向子组件传递数据。子组件利用组件实例的 props
属性定义组件需要接收的参数,在使用组件时通过 attribute
的方式传入参数,如:
{
props: ['name']
}
<child :name="name"></child>
代码解释
JS 代码第 14-18 行:定义了组件 child,并用 props 接收一个参数 name。
JS 代码第 4-12 行:定义了组件 parent,在组件中使用 <child></child>
引用组件,并用 attribute 的方式将 name 传递给组件 child。
在上面的例子中,组件 Child
接收参数 name
,name
可以是字符串、数组、布尔值、对象等类型。但有时候我们需要给接收的参数指定一个特殊的类型和默认值,接下来我们就来介绍一下如何指定 props 的类型和默认值。
3.1 定义props的类型和默认值
在上面的例子中,props 接收一个组件参数数组。实际上,props 也可以接收一个对象,对象key
为组件接收参数的参数名,其值是一个对象,属性 type
用来指定参数的类型,属性 default
用来指定参数的默认值:
{
props: {
name: {
type: String,
default: '句号'
}
}
}
JS 代码第 11-19 行:定义了组件 child,并用 props 接收一个字符串类型的参数 name,其默认值是:句号。
JS 代码第 3-10 行:定义了组件 parent,在组件中使用 <child></child>
两次引用组件,<child :name="name" />
的方式传递 name 值,<child/>
使用默认的 name 值。
TIPS: 注意,给数组和对象类型的 props
设置默认值的时候,需要按照以下的写法:
props: {
detail: {
type: Object,
default: () => {
return {
name: '句号'
}
}
},
loves: {
type: Array,
default: () => {
return []
}
}
}
4. 子组件通过 $emit 传递数据给父组件
介绍完父组件传递数据给子组件的方式,我们再来看看子组件是如何传递数据给父组件的。
子组件通过 $emit
传递事件给父组件,父组件通过 $on
监听事件:
this.$emit('事件名称', '传递的参数')
<child @事件名称="事件触发的方法"/>
代码解释
JS 代码第 19-38 行:定义了组件 child,该组件接收两个参数:1. 字符串类型的 name,默认值为:句号。2. 数字类型的 age,默认值为 18。组件模版中,通过按钮点击事件触发 add 方法,该方法内部通过 $emit
触发事件 add,并将 age + 1 的值作为参数传递。
JS 代码第 3-18 行:定义了组件 parent,在组件中使用 <child :name="name" :age="age" @add="add"/>
引用组件,并绑定 add 事件,当事件 add 触发时调用 methods 中的 add 函数。
5. 非父子组件间数据传递
前面我们介绍了具有父子关系的组件是如何进行数据传递的。但实际上,并不是所有的组件都是父子关系,组件间还有兄弟组件、子孙组件、无关系组件,那么这些组件间是如何进行通信的呢?
相信在学完本节前面的内容之后这个问题并不能难倒大家。
对于兄弟组件的数据通信:它们有共同的父组件,我们可以通过父组件传递的方式实现数据通信。
对于子孙组件的数据通信:可以通过 props 的方式向下逐层传递下去,也可以通过 $emit 将事件向上逐层传递。
对于非关系组件的数据通信:通过使用一个空的Vue实例作为中央事件总线。
5.1 通过公有的父组件进行非父子组件间的通信
假设现在有三个组件分别是<Parent>
、<ChildA>
、<ChildB>
,其中组件<Parent>
是<ChildA>
和<ChildB>
的父组件,<ChildA>
和<ChildB>
为兄弟组件,<ChildA>
和<ChildB>
组件间的通信可以借助<Parent>
来间接传递。它的流程大致是这样:
<ChildA>
通过$emit
将数据传递给<Parent>
,<Parent>
再通过props
将数据传递给<ChildB>
。
代码解释
JS 代码第 18-30 行:定义了组件 detail,它从父组件接收 name 和 age 两个参数。
JS 代码第 3-17 行:定义了组件 person,它通过 $emit 将组件内输入的 name 和 age 传递给父组件。
JS 代码第 38-41 行:接收了组件 person 传递过来的事件,并修改 name 和 age。
HTML 代码第 3 行:将 name 和 age 传递给组件 detail。
5.2 通过使用一个空的 Vue 实例作为中央事件总线
在Vue
中可以使用 EventBus
来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件。
首先我们需要做的是创建事件总线,并将它挂载到Vue
原型上,在实例中通过this.bus.$emit
发送事件,通过this.bus.$on
接收事件。
let bus = new Vue()
Vue.prototype.bus = bus
this.bus.$emit('事件名称', data)
this.bus.$on('事件名称', (data) => {
})
代码解释
JS 代码第 3-4 行:通过 new Vue() 创建一个 vue 实例,并将它挂载在 Vue 的原型上。这样,在 vue 组件中可以通过 this.bus
访问到这个实例对象。
JS 代码第 5-18 行:定义了组件 person,当点击修改按钮的时候通过 this.bus.$emit
发送一个名为 modify
的事件,并将组件内输入的 name 和 age 作为参数传递。
JS 代码第 19-33 行:定义组件 detail,在组件内部通过 this.bus.$on
监听名为 modify 的事件,当事件触发时执行修改操作。
6. 小结
在本小节,我们介绍了组件间的通信方式,主要有以下知识点:
- 父组件通过
props
向子组件传递参数进行数据通信;
- 子组件通过
$emit
向父组件传递事件进行数据通信;
- 兄弟组件通过共同父组件进行数据通信;
- 通过使用一个空的 Vue 实例作为中央事件总线进行非关系层组件的数据通信。