今天面試被問到這個問題,我自己思考的是讓父組件做兩個子組件之間的橋梁,但是我並沒有去說,感覺是有些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:希望大家早日成為前端大神,哈哈哈