面試官:如何使用Event Bus進行Vue組件間通訊?css
本身先想一分鐘!html
譯者注:英語和文筆有限,不對之處歡迎留言斧正!原文地址:css-tricks.com/using-event…vue
默認狀況下,Vue組件間通訊使用的是 props。Props會將數據從父組件傳遞到子組件。例如,有個prop爲 title
的組件:面試
<blog-post title="My journey with Vue"></blog-post>
複製代碼
Props老是從父組件傳到子組件。一旦你的應用程序變的愈來愈複雜,你就會明白所謂的 prop drilling 是什麼意思了。這裏有篇React相關的文章說的就是這個。prop drilling 是將 props 向下一級一級一級的傳給本身子組件的作法 —— 這個過程你懂得!vuex
所以,繁瑣的 prop drilling 可能會給系統帶來潛在的問題(譯者注:特別是數據追溯方面,一層一層的找挺麻煩)。話說回來了,父子組件咱們能夠經過 props 傳遞,其餘無關組件呢?固然經過 vuex、localstorage、session 等都是闊以的。但咱們今天要講的是 Event Bus。微信
什麼是 Event Bus 呢?正如它的名字同樣,咱們能夠將數據從一個組件送到另外一個組件,不管這些組件位於組件樹中的哪一個位置。markdown
讓咱們一塊兒構建一些東西來演示一下 Event Bus 的概念。或許能夠加值、減值以及計算總和的計數器是一個不錯的開始。 掘金 markdown 不能嵌入 Codeopen。因此你能夠狠狠的戳這裏查看示例效果。 下面是截圖: session
要使用 Event Bus,首先咱們須要有一輛車才行,來,初始化一個:app
import Vue from 'vue';
const eventBus = new Vue();
複製代碼
其實就是 new 了一個 Vue 實例給了一個叫 eventBus
變量。這個變量你能夠隨意起名,只要你喜歡就好(譯者注:國際慣例,通常都叫這個名字)。若是你使用的單文件組件 ,你須要把上面的代碼片斷放到單獨的文件裏,而後導出這個變量以便在其餘地方使用:ide
import Vue from 'vue';
export const eventBus = new Vue();
複製代碼
完成後,咱們就能夠在咱們的計數器組件中使用它了。這裏我列舉了一些要作的功能清單:
下面是模板文件中的代碼:
<div id="app">
<h2>Counter</h2>
<h2>{{ count }}</h2>
<input type="number" v-model="entry" />
<div class="div__buttons">
<button class="incrementButton" @click.prevent="handleIncrement">
Increment
</button>
<button class="decrementButton" @click.prevent="handleDecrement">
Decrement
</button>
</div>
<p>{{ text }}</p>
</div>
複製代碼
輸入框中綁定了 entry
屬性,用來增長和減小計數,具體內容取決於用戶的輸入。單擊任一按鈕時,咱們會觸發一個方法,該方法會增長或減小計數的值。最後,<p>
標籤包含的 {{ text }}
內容是咱們打印的消息,顯示咱們對計數器的操做。
下面是咱們 JavaScript 中的內容:
new Vue({
el: '#app',
data() {
return {
count: 0,
text: '',
entry: 0
}
},
created() {
eventBus.$on('count-incremented', () => {
this.text = `Count was increased`
setTimeout(() => {
this.text = '';
}, 3000);
})
eventBus.$on('count-decremented', () => {
this.text = `Count was decreased`
setTimeout(() => {
this.text = '';
}, 3000);
})
},
methods: {
handleIncrement() {
this.count += parseInt(this.entry, 10);
eventBus.$emit('count-incremented')
this.entry = 0;
},
handleDecrement() {
this.count -= parseInt(this.entry, 10);
eventBus.$emit('count-decremented')
this.entry = 0;
}
}
})
複製代碼
經過查看上面的代碼你已經注意到了,咱們已經跳到車上了,立刻發車!
咱們要作的第一件事就是創建一個從一個組件發送到另外一個組件的路。如何鋪路呢?經過 eventBus.$emit()
(使用 emit 做爲發送聽起來挺花裏胡哨)。eventBus.$emit
消息發送事件在兩個方法中, handleIncrement
和 handleDecrement
,這倆方法監聽用戶輸入後的提交操做,一旦他們被觸發,咱們的 event bus 就會派發事件並開始在組件間發送數據。
你可能已經注意到了,咱們正在 created()
生命週期鉤子中使用 eventBus.$on()
監聽這兩個事件。請注意,監聽事件和發送事件的事件名必須保持一致。當 eventBus 識別出派發的事件名後,就會調用對應的監聽函數 — 在監聽函數中,咱們設置一個文原本顯示咱們執行的操做,並使其3s後消失。
假設咱們正在開發一個我的資料頁面,用戶能夠在這個頁面更新本身的暱稱和電子郵件,而後在不刷新頁面的狀況下查看更新。這個可使用 event bus 輕鬆完成,即使咱們此次處理的是兩個組件:用戶資料組件和修改資料提交表單組件。
示例代碼戳這裏,下面是截圖:
這裏是 html 代碼:
<div class="container">
<!-- 我的資料 -->
<div id="profile">
<h2>Profile</h2>
<div>
<p>Name: {{name}}</p>
<p>Email: {{ email }}</p>
</div>
</div>
<!-- 修改資料表單-->
<div id="edit__profile">
<h2>Enter your details below:</h2>
<form @submit.prevent="handleSubmit">
<div class="form-field">
<label>Name:</label>
<input type="text" v-model="user.name" />
</div>
<div class="form-field">
<label>Email:</label>
<input type="text" v-model="user.email" />
</div>
<button>Submit</button>
</form>
</div>
</div>
複製代碼
咱們將傳遞 ids
(user.name
和 user.email
)給相應的組件。首先,讓咱們給修改我的資料(edit__profile
)組件設置模板。該組件包含咱們在 html 模板中綁定的屬性。一樣的,當提交事件觸發後,咱們使用 eventBus 來派發事件,並傳遞表單數據。看下面的代碼:
new Vue({
el: "#edit__profile",
data() {
return {
user: {
name: '',
email: ''
}
}
},
methods: {
handleSubmit() {
eventHub.$emit('form-submitted', this.user)
this.user = {}
}
}
})
複製代碼
從修改資料表單中傳遞出來的數據將會應用在我的資料組件。也就是說,當公交車到站(監聽到派發事件)後,就會接受到發送過來的數據(name
和 email
)從而實現頁面更新。看下面的代碼:
new Vue({
el: '#profile',
data() {
return {
name: '',
email: ''
}
},
created() {
eventHub.$on('form-submitted', ({ name, email}) => {
this.name = name;
this.email = email
})
}
})
複製代碼
他們的口袋都裝滿了,如今他們要作的就是回家。
是否是很酷? 即使修改資料組件和我的資料展現組件並不相關 — 或不是直接的父子關係),他們也是能夠相互通訊的,由於他們都坐同一班車。
在我設計響應式應用系統中我發現 Event Bus 確實很好用 — 特別是,當我基於服務端數據來更新組件時並不會形成頁面刷新。並且,派發的事件能夠同時被多個組件監聽。
若是你有其餘有趣的使用 Event Bus 的場景,歡迎留言。🚌
最後,下面是我維護的一個Q羣,歡迎掃碼進羣哦,讓咱們一塊兒交流學習吧。也能夠加我我的微信:G911214255 ,備註 掘金
便可。