vue 兄弟组件是如何通信的

今天面试被问到这个问题,我自己思考的是让父组件做两个子组件之间的桥梁,但是我并没有去说,感觉是有些low啊,面试完了赶紧查查是怎么通信的;

就是我自己设想的这种方法也是解决问题的一种方法;

兄弟组件通讯

在Vue中实现兄弟组件的通讯也有几种方法,其中一种方法是让父组件允当两个子组件之间的中间件(中继);

另一种就是使用EventBus(事件总线),它允许两个子组件之间直接通讯,而不需要涉及父组件。

这里就要好好了解下EventBus(事件总线)的概念了;

1、通过父组件进行兄弟组件之间通讯

先来看第一个方法,就是让兄弟组件通过一个共同的父组件彼此通讯。

我们还是通过示例来学习。接下来的这个示例包含父组件和两个子组件,这两个子组件是兄弟组件。单击兄弟组件上的按钮,可以看到他们之间可以相互通讯。

 

 

 首先创建ParentCard组件:

 1 <!-- ParentCard.vue -->
 2 
 3 <template>
 4 
 5   <div class="card">
 6 
 7     <div class="card-header">
 8 
 9       <h5 v-text="theCardTitle"></h5>
10 
11       <button @click="momSaidChill" v-if="stopFighting()" class="btn">停止通讯</button>
12 
13     </div>
14 
15     <div class="card-body">
16 
17       <brother-card :messageSon="messageson" @brotherSaid="messageDaughter($event)"></brother-card>
18 
19       <sister-card :messageDaughter="messagedaughter" @sisterSaid="messageSon($event)"></sister-card>
20 
21     </div>
22 
23   </div>
24 
25 </template>
26 
27 <script>
28 
29 import BrotherCard from './BrotherCard';
30 
31 import SisterCard from './SisterCard'
32 
33 export default {
34 
35   name: 'ParentCard',
36 
37   data: () => ({
38 
39     theCardTitle: '父组件',
40 
41     messagedaughter:'',
42 
43     messageson:''
44 
45   }),
46 
47   components: {
48 
49     BrotherCard,
50 
51     SisterCard
52 
53   },
54 
55   methods: {
56 
57     messageDaughter(message) {
58 
59       this.messagedaughter = message;
60 
61     },
62 
63     messageSon(message) {
64 
65       this.messageson = message;
66 
67     },
68 
69     stopFighting() {
70 
71       if (this.messagedaughter && this.messageson) {
72 
73         return true
74 
75       }
76 
77       return false
78 
79     },
80 
81     momSaidChill() {
82 
83       this.messagedaughter = '',
84 
85       this.messageson = ''
86 
87     }
88 
89   }
90 
91 }; 
92 
93 </script>

 

创建SisterCard组件:

 1 <!-- SisterCard.vue -->
 2 
 3 <template>
 4 
 5   <div class="message">
 6 
 7     <div class="message-header">
 8 
 9       <h5 v-text="theCardTitle"></h5>
10 
11     </div>
12 
13     <div class="message-body">
14 
15       <p class="message-text">我是Sister组件</p>
16 
17       <button @click="messageBrother" class="btn">给哥哥发消息</button>
18 
19       <div v-if="messageDaughter" class="alert" v-html="messageDaughter"></div>
20 
21     </div>
22 
23   </div>
24 
25 </template>
26 
27 <script>
28 
29 export default {
30 
31   name: 'SisterCard',
32 
33   props: ['messageDaughter'],
34 
35   data: () => ({
36 
37     theCardTitle: '子组件2'
38 
39   }),
40 
41   methods: {
42 
43     messageBrother() {
44 
45       this.$emit('sisterSaid', '妈妈说,该做作业了!(^_^)!!!')
46 
47     }
48 
49   }
50 
51 }
52 
53 </script>

 

 

接着创建BrotherCard组件:

 1 <!-- BrotherCard.vue -->
 2 
 3 <template>
 4 
 5   <div class="message">
 6 
 7     <div class="message-header">
 8 
 9       <h5 v-text="theCardTitle"></h5>
10 
11     </div>
12 
13     <div class="message-body">
14 
15       <p class="message-text">我是Brother组件</p>
16 
17       <button @click="messageSister" class="btn">给妹妹发消息</button>
18 
19       <div v-if="messageSon" class="alert" v-html="messageSon"></div>
20 
21     </div>
22 
23   </div>
24 
25 </template>
26 
27 <script>
28 
29 export default {
30 
31   name: 'BrotherCard',
32 
33   props: ['messageSon'],
34 
35   data: () => ({
36 
37     theCardTitle: '子组件1'
38 
39   }),
40 
41   methods: {
42 
43     messageSister() {
44 
45       this.$emit('brotherSaid', '妈妈说,该做作业了!(^_^)!!!')
46 
47     }
48 
49   }
50 
51 }
52 
53 </script>

 

最终效果如下:

接下来简单看看这个实现过程。

SisterCard通过ParentCardBrotherCard通讯

首先来看SisterCard是如何与BrotherCard通讯的。从示例中可以看出,他们两之间的通讯是通过其父组件ParentCard作为中间媒介来进行通讯的。

我们在SisterCard组件的<template>中为messageBrother()方法设置了一个@click事件来监听该事件。

<button @click="messageBrother" class="btn">给哥哥发消息</button>

当用户点击SisterCard中的“给哥哥发消息”将会触发messageBrother()方法。在这个方法中,将发出一个sisterSaid事件,并且把妈妈说,该做作业了!(^_^)!!!信息发送出去。

1 methods: {
2 
3   messageBrother() {
4 
5     this.$emit("sisterSaid", "妈妈说,该做作业了!(^_^)!!!");
6 
7   } 
8 
9 }

 

ParentCard<template>中定制了一个@sisterSaid事件侦听器,它触发了messageSon()方法。所以父组件在这两个兄弟组件之间起到了传递的作用。

<sister-card :messageDaughter="messagedaughter" @sisterSaid="messageSon($event)"></sister-card>

另外在ParentCard组件中声明了messageSon()方法,该方法接受上面发送的自定义事件,并将其设置为messageson属性。

这样一来,ParentCard组件中messageson就由空字符串变成了妈妈说,该做作业了!(^_^)!!!

接着在ParentCard组件自定义标签<brother-card>通过:messageSon="messageson"的方式将messageson属性绑定到<brother-card>

<brother-card :messageSon="messageson" @brotherSaid="messageDaughter($event)"></brother-card>

这个时候在BrotherCard组件中设置props的属性值为messageSon。这样就可以访问源自于SisterCard组件的数据,并且该数据在BrotherCard中显示。

props: ["messageSon"],

最后在BrotherCard组件就可以使用该数据。我们可以通过v-if指令来查看messageSon是否有任何有用的数据,如果有,那么就在div.alert中显示该消息:

<div v-if="messageSon" class="alert" v-html="messageSon"></div>

上面的描述过程也适用于BrotherCard通过ParentCardSisterCard进行数据通讯。

 

2、通过EventBus进行兄弟间组件通讯

随着应用程序越来越庞大,通过父组件来传递所有内容会把事情变得越来越棘手。不过我们还有另一种选择,那就是使用EventBus架起兄弟之间通讯的桥梁。接下来看看我们是如何利用这一点一完成兄弟组件之间的数据通讯。

我们同样基于上面的示例来做修改。接下来的示例中,ParentCard组件包含了SisterCardBrotherCard两个子组件,而且这两个子组件是兄弟组件。

首先在main.js文件中定义一个新的eventBus对象,其实他是一个全新的Vue实例:

 1 // main.js
 2 
 3 import Vue from 'vue'
 4 
 5 import App from './App'
 6 
 7 export const eventBus = new Vue()
 8 
 9 new Vue({
10 
11   el: '#app',
12 
13   render: h => h(App)
14 
15 })

 

接着在新创建的BrotherCard组件导入main.js

1 <!-- BrotherCard.vue -->
2 
3 <script>
4 
5 import { eventBus } from '../main'
6 
7 </script>

 

eventBus实例现在将成为BrotherCard组件中发出事件的实例。现在我们可以使用eventBus.$emit来替代上例中的this.$emiteventBus是一个Vue实例,而且eventBus有这个$emit方法,这就是我们能够这么用的原因。这样做同样会触发相同的自定义事件名称和消息。

1 methods: {
2 
3   messageSister() {
4 
5     eventBus.$emit('brotherSaid', '妈妈说,该做作业了!(^_^)!!!')
6 
7   }
8 
9 } 

同样可以在SisterCard组件中引入eventBus

<script>

import { eventBus } from '../main'

</script>

created()生命周期钩子添加到SisterCard组件。在created()钩子中添加eventBus启动自定义事件的侦听器。当使用SisterCard组件时,该侦听器将开始运行并且会保持运行。下面的代码只是侦听brotherSaid自定义事件,然后触发回调,将作为自定义事件有效负载传递的消息分配给fromBrother

1 created() {
2 
3   eventBus.$on('brotherSaid', (message) => {
4 
5     this.fromBrother = message
6 
7   })
8 
9 } 

这样就可以有条件地显示来自BrotherCard的信息:

<div v-if="fromBrother" class="alert" v-html="fromBrother"></div>

上面看到的是如何通过eventBus实现SisterCardBrotherCard传递数据的方式,反之,BrotherCard向SisterCard`传递数据也可以使用类似的方式。

最终代码如下:

 1 <!-- SisterCard.vue -->
 2 
 3 <template>
 4 
 5   <div class="message">
 6 
 7     <div class="message-header">
 8 
 9       <h5 v-text="theCardTitle"></h5>
10 
11     </div>
12 
13     <div class="message-body">
14 
15       <p class="message-text">我是Sister组件</p>
16 
17       <button @click="messageBrother" class="btn">给哥哥发消息</button>
18 
19       <div v-if="fromBrother" class="alert" v-html="fromBrother"></div>
20 
21     </div>
22 
23   </div>
24 
25 </template>
26 
27 <script>
28 
29 import { eventBus } from "../main";
30 
31 export default {
32 
33   name: "SisterCard",
34 
35   data: () => ({
36 
37     theCardTitle: "Sister Card",
38 
39     fromBrother: ""
40 
41   }),
42 
43   methods: {
44 
45     messageBrother() {
46 
47       eventBus.$emit("sisterSaid", "妈妈说,该做作业了!(^_^)!!!");
48 
49     }
50 
51   },
52 
53   created() {
54 
55     eventBus.$on("brotherSaid", message => {
56 
57       this.fromBrother = message;
58 
59     });
60 
61   }
62 
63 };
64 
65 </script>
 1 <!-- BrotherCard.vue -->
 2 
 3 <template>
 4 
 5   <div class="message">
 6 
 7     <div class="message-header">
 8 
 9       <h5 v-text="theCardTitle"></h5>
10 
11     </div>
12 
13     <div class="message-body">
14 
15       <p class="message-text">我是Brother组件</p>
16 
17       <button @click="messageSister" class="btn">给妹妹发消息</button>
18 
19       <div v-if="fromSister" class="alert" v-html="fromSister"></div>
20 
21     </div>
22 
23   </div>
24 
25 </template>
26 
27 <script>
28 
29 import { eventBus } from "../main.js";
30 
31 export default {
32 
33   name: "BrotherCard",
34 
35   data: () => ({
36 
37     theCardTitle: "Brother Card",
38 
39     fromSister: ""
40 
41   }),
42 
43   methods: {
44 
45     messageSister() {
46 
47       eventBus.$emit("brotherSaid", "妈妈说,该做作业了!(^_^)!!!");
48 
49     }
50 
51   },
52 
53   created() {
54 
55     eventBus.$on("sisterSaid", message => {
56 
57       this.fromSister = message;
58 
59     });
60 
61   }
62 
63 };
64 
65 </script>

 

最后创建的ParentCard组件,我们可以像下面这样编码:

 1 <!-- ParentCard -->
 2 
 3 <template>
 4 
 5   <div class="card">
 6 
 7     <div class="card-header">
 8 
 9       <h5 v-text="theCardTitle"></h5>
10 
11     </div>
12 
13     <div class="card-body">
14 
15       <brother-card></brother-card>
16 
17       <sister-card></sister-card>
18 
19     </div>
20 
21   </div>
22 
23 </template>
24 
25 <script>
26 
27 import BrotherCard from "./BrotherCard";
28 
29 import SisterCard from "./SisterCard";
30 
31 export default {
32 
33   name: "ParentCard",
34 
35   data: () => ({
36 
37     theCardTitle: "Parent Card"
38 
39   }),
40 
41   components: {
42 
43     BrotherCard,
44 
45     SisterCard
46 
47   }
48 
49 };
50 
51 </script>

 

总结

在本教程中,我们学习了在Vue中如何实现组件之间的通讯。通过实例看到了如何实现父组件向子组件,子组件向父组件以及兄弟组件间的数据通讯。简单的根据为:

  • 通过props可以实现父组件向子组件发送数据
  • 通过自定义事件可以实现子组件向父组件发送数据
  • 兄弟组件数据通讯除了借助共同的父组件做为通讯桥梁之外,还可以通过eventBus来让兄弟之间组件进行数据通讯

最后用一张图来简单的描述一下:

 

原文: https://www.w3cplus.com/vue/component-communication.html 

 ps:希望大家早日成为前端大神,哈哈哈


 

posted @ 2020-10-21 13:31  之鹿喵  阅读(6850)  评论(0编辑  收藏  举报