Vue 组件间通信

前言

组件(Component) 是 Vue 最强大的功能之一,使用组件化的开发方式可以提高 Web 应用的可维护性。不同组件需要协同合作,组件间通信是必不可少的。在 Vue 中,父子组件之间的通信可以总结为 props down, events up,非父子组件之间通信主要是借助于 Event Bus 来实现,下面以几个实例来进行详细探讨。本文的代码都在 这里

父组件向子组件通信

父组件向子组件通信是通过 props 来传递的。

1.创建一个子组件 Child.vue,在子组件中显式地用 props 属性来声明需要从父组件获取的数据:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div class="child">
<h2>子组件Child</h2>
<p>从父组件获取的数据为 {{ message }}</p>
</div>
</template>
<script>
export default {
props: ['message']
}
</script>

2.在父组件 App.vue 中注册 Child 组件,使用 Child 组件时在标签中添加 message 属性,并赋值,message 属性的值可以使用 v-bind 动态绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div id="app">
<h1>父组件 Parent</h1>
<Child :message="parentMsg"></Child>
</div>
</template>
<script>
import Child from './components/Child';
export default {
name: 'app',
data () {
return {
parentMsg: 'Hello, Mr.Song!'
}
},
components: {
Child
}
}
</script>

3.打开浏览器,查看效果如下:

父组件向子组件通信

可以看见,子组件拿到了父组件传递过来的 Hello, Mr.Song!,父组件向子组件通信成功。

子组件向父组件通信

在 Vue 中,每个 Vue 实例都实现了事件接口,我们可以使用 $emit(eventName) 来触发事件,并用 $on(eventName) 来监听事件。子组件向父组件通信就是利用这套机制,在子组件中触发自定义事件,并在父组件中监听该事件而实现的。

1.在上一节的 Child 组件中,添加一个按钮,为按钮绑定一个点击事件,在点击事件的处理函数中,使用 $emit 来触发一个自定义事件 childEvent,并传递参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="child">
<h2>子组件Child</h2>
<p>从父组件获取的数据为 {{ message }}</p>
<button @click="sendMsgToParent">向父组件传值</button>
</div>
</template>
<script>
export default {
props: ['message'],
methods: {
sendMsgToParent: function() {
this.$emit('childEvent', 'Wow, this is a message from child!');
}
}
}
</script>

2.在父组件 App.vue 的 Child 组件标签中监听该自定义的 childEvent 事件,并添加一个该事件的处理函数:

1
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
<template>
<div id="app">
<h1>父组件 Parent</h1>
<p>从子组件获取的数据为{{ childMsg }}</p>
<Child :message="parentMsg" @childEvent="handleMsgFromChild"></Child>
</div>
</template>
<script>
import Child from './components/Child';
export default {
name: 'app',
data () {
return {
parentMsg: 'Hello, Mr.Song!',
childMsg: 'Initial message.'
}
},
methods: {
handleMsgFromChild: function(data) {
this.childMsg = data;
}
},
components: {
Child
}
}
</script>

3.打开浏览器,点击 向父组件传值 按钮后,可以看见父组件中 Initial message. 变成了 Wow, this is a message from child!,子组件向父组件通信成功:

子组件向父组件通信

非父子组件之间通信

在 Vue 中,非父子组件之间的通信需要借助于 EventBus,主要思想就是使用一个空的 Vue 实例作为中央事件总线,利用这个 Vue 实例在两个组件内分别触发和接收事件。

1.新建一个 eventBus.js,在该文件内创建一个 Vue 实例作为中央事件总线:

1
2
3
import Vue from 'Vue';
export default new Vue();

2.创建一个 FirstSibling 组件,引入 eventBus 事件总线,并在组件中使用 eventBus 触发一个自定义 siblingEvent 事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="child">
<h2>firstSibling 组件</h2>
<button @click="sendMsg">向兄弟组件传值</button>
</div>
</template>
<script>
import bus from '../assets/eventBus';
export default {
methods: {
sendMsg: function () {
bus.$emit('siblingEvent', 'A message from firstSibling!');
}
}
}
</script>

3.再创建一个 SecondSibling 组件,也引入 eventBus 事件总线,并在该组件中使用 eventBus 监听 siblingEvent 事件,获取传递过来的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<div class="child">
<h2>secondSibling 组件</h2>
<p>从兄弟组件获取到的数据为 {{ siblingMsg }}</p>
</div>
</template>
<script>
import bus from '../assets/eventBus';
export default {
data() {
return {
siblingMsg: 'Initial message.'
}
},
mounted() {
const self = this;
bus.$on('siblingEvent', function (data) {
self.siblingMsg = data;
})
}
}
</script>

4.在共同父组件 App.vue 中注册这两个组件,并在模板中添加这两个组件的标签:

1
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
<template>
<div id="app">
<h1>父组件 Parent</h1>
<p>从子组件获取的数据为 {{ childMsg }}</p>
<Child :message="parentMsg" @childEvent="handleMsgFromChild"></Child>
<FirstSibling></FirstSibling>
<SecondSibling></SecondSibling>
</div>
</template>
<script>
import Child from './components/Child';
import FirstSibling from './components/FirstSibling';
import SecondSibling from './components/SecondSibling';
export default {
name: 'app',
data () {
return {
parentMsg: 'Hello, Mr.Song!',
childMsg: 'Initial message.'
}
},
methods: {
handleMsgFromChild: function(data) {
this.childMsg = data;
}
},
components: {
Child,
FirstSibling,
SecondSibling
}
}
</script>

5.打开浏览器,点击 FirstSibling 组件中的 向兄弟组件传值 按钮,可以看见 SecondSibling 组件中 Initial message. 变成了 A message from FirstSibling!,组件间通信成功:

非父子组件通信

结语

在 Vue 的组件间通信中,无论是父子组件还是非父子组件之间,都需要一个中间介质。父组件向子组件通信的核心是 props 属性,子组件向父组件通信的核心是自定义事件 events,非父子组件之间通信的核心是中央事件总线 eventBus 结合自定义事件 events。不过这些都只适合与比较简单的项目,对于更复杂的项目,Vue 提供了一个状态管理模式 Vuex 来处理。

------ 本文结束 ------
坚持原创技术分享,您的支持将鼓励我继续创作!