今天面试被问到这个问题,我自己思考的是让父组件做两个子组件之间的桥梁,但是我并没有去说,感觉是有些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
通过ParentCard
与BrotherCard
通讯
首先来看SisterCard
是如何与BrotherCard
通讯的。从示例中可以看出,他们两之间的通讯是通过其父组件ParentCard
作为中间媒介来进行通讯的。
我们在SisterCard
组件的<template>
中为messageBrother()
方法设置了一个@click
事件来监听该事件。
<button
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
通过ParentCard
与SisterCard
进行数据通讯。
2、通过EventBus进行兄弟间组件通讯
随着应用程序越来越庞大,通过父组件来传递所有内容会把事情变得越来越棘手。不过我们还有另一种选择,那就是使用EventBus
架起兄弟之间通讯的桥梁。接下来看看我们是如何利用这一点一完成兄弟组件之间的数据通讯。
我们同样基于上面的示例来做修改。接下来的示例中,ParentCard
组件包含了SisterCard
和BrotherCard
两个子组件,而且这两个子组件是兄弟组件。
首先在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.$emit
。eventBus
是一个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
实现SisterCard
向BrotherCard
传递数据的方式,反之,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:希望大家早日成为前端大神,哈哈哈