vue 兄弟元件是如何通訊的
今天面試被問到這個問題,我自己思考的是讓父元件做兩個子元件之間的橋樑,但是我並沒有去說,感覺是有些low啊,面試完了趕緊查查是怎麼通訊的;
就是我自己設想的這種方法也是解決問題的一種方法;
兄弟元件通訊
在Vue中實現兄弟元件的通訊也有幾種方法,其中一種方法是讓父元件允當兩個子元件之間的中介軟體(中繼);
另一種就是使用EventBus
(事件匯流排),它允許兩個子元件之間直接通訊,而不需要涉及父元件。
這裡就要好好了解下EventBus
(事件匯流排)的概念了;
1、通過父元件進行兄弟元件之間通訊
先來看第一個方法,就是讓兄弟元件通過一個共同的父元件彼此通訊。
我們還是通過示例來學習。接下來的這個示例包含父元件和兩個子元件,這兩個子元件是兄弟元件。單擊兄弟元件上的按鈕,可以看到他們之間可以相互通訊。
首先建立ParentCard
元件:
<!-- ParentCard.vue -->
<template>
<div class="card">
<div class="card-header">
<h5 v-text="theCardTitle"></h5>
<button @click="momSaidChill" v-if="stopFighting()" class="btn">停止通訊</button>
</div>
<div class="card-body">
<brother-card :messageSon="messageson" @brotherSaid="messageDaughter($event)"></brother-card>
<sister-card :messageDaughter="messagedaughter" @sisterSaid="messageSon($event)"></sister-card>
</div>
</div>
</template>
<script>
import BrotherCard from './BrotherCard';
import SisterCard from './SisterCard'
export default {
name: 'ParentCard',
data: () => ({
theCardTitle: '父元件',
messagedaughter:'',
messageson:''
}),
components: {
BrotherCard,
SisterCard
},
methods: {
messageDaughter(message) {
this.messagedaughter = message;
},
messageSon(message) {
this.messageson = message;
},
stopFighting() {
if (this.messagedaughter && this.messageson) {
return true
}
return false
},
momSaidChill() {
this.messagedaughter = '',
this.messageson = ''
}
}
};
</script>
建立SisterCard
元件:
<!-- SisterCard.vue -->
<template>
<div class="message">
<div class="message-header">
<h5 v-text="theCardTitle"></h5>
</div>
<div class="message-body">
<p class="message-text">我是Sister元件</p>
<button @click="messageBrother" class="btn">給哥哥發訊息</button>
<div v-if="messageDaughter" class="alert" v-html="messageDaughter"></div>
</div>
</div>
</template>
<script>
export default {
name: 'SisterCard',
props: ['messageDaughter'],
data: () => ({
theCardTitle: '子元件2'
}),
methods: {
messageBrother() {
this.$emit('sisterSaid', '媽媽說,該做作業了!(^_^)!!!')
}
}
}
</script>
接著建立BrotherCard
元件:
<!-- BrotherCard.vue -->
<template>
<div class="message">
<div class="message-header">
<h5 v-text="theCardTitle"></h5>
</div>
<div class="message-body">
<p class="message-text">我是Brother元件</p>
<button @click="messageSister" class="btn">給妹妹發訊息</button>
<div v-if="messageSon" class="alert" v-html="messageSon"></div>
</div>
</div>
</template>
<script>
export default {
name: 'BrotherCard',
props: ['messageSon'],
data: () => ({
theCardTitle: '子元件1'
}),
methods: {
messageSister() {
this.$emit('brotherSaid', '媽媽說,該做作業了!(^_^)!!!')
}
}
}
</script>
最終效果如下:
接下來簡單看看這個實現過程。
SisterCard
通過ParentCard
與BrotherCard
通訊
首先來看SisterCard
是如何與BrotherCard
通訊的。從示例中可以看出,他們兩之間的通訊是通過其父元件ParentCard
作為中間媒介來進行通訊的。
我們在SisterCard
元件的<template>
中為messageBrother()
方法設定了一個@click
事件來監聽該事件。
<button
methods: {
messageBrother() {
this.$emit("sisterSaid", "媽媽說,該做作業了!(^_^)!!!");
}
}
在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例項:
// main.js
import Vue from 'vue'
import App from './App'
export const eventBus = new Vue()
new Vue({
el: '#app',
render: h => h(App)
})
接著在新建立的BrotherCard
元件匯入main.js
:
<!-- BrotherCard.vue -->
<script>
import { eventBus } from '../main'
</script>
eventBus
例項現在將成為BrotherCard
元件中發出事件的例項。現在我們可以使用eventBus.$emit
來替代上例中的this.$emit
。eventBus
是一個Vue例項,而且eventBus
有這個$emit
方法,這就是我們能夠這麼用的原因。這樣做同樣會觸發相同的自定義事件名稱和訊息。
methods: {
messageSister() {
eventBus.$emit('brotherSaid', '媽媽說,該做作業了!(^_^)!!!')
}
}
同樣可以在SisterCard
元件中引入eventBus
:
<script>
import { eventBus } from '../main'
</script>
將created()
生命週期鉤子新增到SisterCard
元件。在created()
鉤子中新增eventBus
啟動自定義事件的偵聽器。當使用SisterCard
元件時,該偵聽器將開始執行並且會保持執行。下面的程式碼只是偵聽brotherSaid
自定義事件,然後觸發回撥,將作為自定義事件有效負載傳遞的訊息分配給fromBrother
。
created() {
eventBus.$on('brotherSaid', (message) => {
this.fromBrother = message
})
}
這樣就可以有條件地顯示來自BrotherCard
的資訊:
<div v-if="fromBrother" class="alert" v-html="fromBrother"></div>
上面看到的是如何通過eventBus
實現SisterCard
向BrotherCard
傳遞資料的方式,反之,BrotherCard
向SisterCard`傳遞資料也可以使用類似的方式。
最終程式碼如下:
<!-- SisterCard.vue -->
<template>
<div class="message">
<div class="message-header">
<h5 v-text="theCardTitle"></h5>
</div>
<div class="message-body">
<p class="message-text">我是Sister元件</p>
<button @click="messageBrother" class="btn">給哥哥發訊息</button>
<div v-if="fromBrother" class="alert" v-html="fromBrother"></div>
</div>
</div>
</template>
<script>
import { eventBus } from "../main";
export default {
name: "SisterCard",
data: () => ({
theCardTitle: "Sister Card",
fromBrother: ""
}),
methods: {
messageBrother() {
eventBus.$emit("sisterSaid", "媽媽說,該做作業了!(^_^)!!!");
}
},
created() {
eventBus.$on("brotherSaid", message => {
this.fromBrother = message;
});
}
};
</script>
<!-- BrotherCard.vue -->
<template>
<div class="message">
<div class="message-header">
<h5 v-text="theCardTitle"></h5>
</div>
<div class="message-body">
<p class="message-text">我是Brother元件</p>
<button @click="messageSister" class="btn">給妹妹發訊息</button>
<div v-if="fromSister" class="alert" v-html="fromSister"></div>
</div>
</div>
</template>
<script>
import { eventBus } from "../main.js";
export default {
name: "BrotherCard",
data: () => ({
theCardTitle: "Brother Card",
fromSister: ""
}),
methods: {
messageSister() {
eventBus.$emit("brotherSaid", "媽媽說,該做作業了!(^_^)!!!");
}
},
created() {
eventBus.$on("sisterSaid", message => {
this.fromSister = message;
});
}
};
</script>
最後建立的ParentCard
元件,我們可以像下面這樣編碼:
<!-- ParentCard -->
<template>
<div class="card">
<div class="card-header">
<h5 v-text="theCardTitle"></h5>
</div>
<div class="card-body">
<brother-card></brother-card>
<sister-card></sister-card>
</div>
</div>
</template>
<script>
import BrotherCard from "./BrotherCard";
import SisterCard from "./SisterCard";
export default {
name: "ParentCard",
data: () => ({
theCardTitle: "Parent Card"
}),
components: {
BrotherCard,
SisterCard
}
};
</script>
總結
在本教程中,我們學習了在Vue中如何實現元件之間的通訊。通過例項看到了如何實現父元件向子元件,子元件向父元件以及兄弟元件間的資料通訊。簡單的根據為:
- 通過
props
可以實現父元件向子元件傳送資料 - 通過自定義事件可以實現子元件向父元件傳送資料
- 兄弟元件資料通訊除了藉助共同的父元件做為通訊橋樑之外,還可以通過
eventBus
來讓兄弟之間元件進行資料通訊
最後用一張圖來簡單的描述一下:
原文:https://www.w3cplus.com/vue/component-communication.html
ps:希望大家早日成為前端大神,哈哈哈