Vue.js
ItIron2020
我們在昨天介紹了vue-cli這個好東西,利用它可以超快速的打造一個完整的vue專案,同時也簡單介紹了專案內的結構,今天我們要探討的主題與之前提過的組件溝通有關係,同時也是為了之後的集中資料管理鋪路,算是一個複習+預習的過程,那我們就馬上開始吧!
是的,你說的沒錯,在之前的todo-list組件與父層app組件的範例中,我們確實利用了props & emit實現了父子層之間的溝通,但不知道你有沒有想過萬一今天是以下的情況呢?
<template>
<div>
<component-a></component-a>
<component-b></component-b>
</div>
</template>
很不巧的這兩個組件的資料會相互影響,比方說一邊是顯示資料、另一邊則是新增/刪除資料,很明顯你無法單靠props & emit達成子層間的資料溝通,這時候就需要EventBus的概念出場了!
不用緊張,程式語言的一大特色就是會將很單純的概念用很複雜的名詞包起來,讓我們在講話時聽起來很高端、大氣、上檔次,實際上EventBus就只是一個vue實體而已
也就是說大概是這樣的玩意兒
// EventBus.js
import Vue from "vue"
export const EventBus = new Vue()
為什麼這樣簡單的一個vue實體能協助我們進行組件間的溝通呢? 請你回想一下emit的概念
子層自訂事件傳給父層 -------> 父層監聽此事件並執行對應的handler
EventBus也是完全相同的概念,只是今天它是一個獨立的實體且作為所有組件的自訂事件監聽者,我有找到一個還不錯的概念圖
簡單說就是我們所有的組件共同搭乘一輛公車,那今天每個組件都跟司機說若發生A情況,那就請你做B事件,由於每個組件都在同一輛車上,處理時自然也會相互影響到!
上方的說明可能讓你更加困惑了,my bad! 還是實際來做一次吧!
我們接續昨天建立的vue-cli專案,若沒有的話就直接利用vue create再建一個即可! 首先請你到src目錄下新增一個EventBus.js檔案,並寫入以下的內容
// EventBus.js
import Vue from "vue"
export const EventBus = new Vue()
接著到src/components新增以下兩隻檔案,並分別寫入指定的內容
// DisplayNumbers.vue
<template>
<div>
<h2>{{ numbers }}</h2>
</div>
</template>
<script>
export default {
data() {
return {
numbers: [1,2,3,5,7]
}
},
}
</script>
// AddNumbers.vue
<template>
<div>
<label for="number"></label>
<input
type="text"
name="number"
placeholder="Enter a number"
v-model="number"
/>
<button @click="addNumber">Add number</button>
</div>
</template>
<script>
export default {
data() {
return {
number: 0
}
},
methods: {
addNumber() {
console.log(this.number)
}
}
}
</script>
最後回到App.vue,將原本預設的內容砍的乾乾淨淨,並引入兩個子元件,最終改寫為下方的程式碼。
<template>
<div id="app">
<DisplayNumbers />
<AddNumbers />
</div>
</template>
<script>
import AddNumbers from './components/AddNumbers.vue'
import DisplayNumbers from './components/DisplayNumbers.vue'
export default {
name: 'App',
components: {
AddNumbers,
DisplayNumbers
}
}
</script>
小提醒
有人可能會好奇,我們在之前的文章說過在template使用組件時需要轉為kebab case並用-連接,不過實際上你可以在template中直接用你在下方componets屬性的名稱,只不過在解析的時候它會被視為轉為kebab case的結果,也就是說,下方兩者最終會有一樣的效果
<AddNumbers/> => <add-numbers></add-numbers>
現階段你就把它當成一種short hand即可,不需要太在意:D
完成以上的操作後,請你在終端機輸入npm run serve啟動專案,沒意外的話你會看到以下的畫面。
至此我們前置作業就完成了!
先思考一下,我們要如何利用AddNumbers組件去影響DisplayNumbers組件?
這樣看起來就簡單多了,首先我們到AddNumbers.vue修改一下程式碼!
// AddNumbers.vue
import {EventBus} from '../EventBus.js' // 引入EventBus實體
export default {
data() {
return {
number: 0
}
},
methods: {
addNumber() {
EventBus.$emit('addNumber',parseInt(this.number))
}
}
}
</script>
我們在其中引入EventBus這個vue實體,並在點擊按鈕時註冊一個addNumber事件給它,同時將this.number作為payload傳進去,接著我們需要修改一下負責顯示的組件
// DisplayNumbers.vue
import {EventBus} from '../EventBus.js'
export default {
data() {
return {
numbers: [1,2,3,5,7]
}
},
methods: {
handleAddNumber() {
EventBus.$on('addNumber',(payload)=>{
this.numbers.push(payload)
})
}
},
created() {
this.handleAddNumber() // 在建立時就開始監聽
}
}
</script>
在DisplayNumbers組件做的事情大同小異,我們一樣先引入了EventBus,同時建立一個methods監聽addNumber事件,並傳入一個callback告訴它這事件發生時要做什麼,最後則是在created hooks就開始監聽這個事件! 你自然也可以在mounted階段做!
最後請你回到頁面上,隨便輸入一個數字並按下按鈕,你會發現它順利的運作了!
我們今天介紹了EventBus的概念,藉由EventBus可以實現同層組件的互相溝通,在專案規模小的時候不失為一個很棒的解決方案! 其中的概念並不複雜,有興趣的話也可以跟著教學做一次,相信會讓你更印象深刻的! 那我們就明天再見囉! 祝大家中秋佳節愉快!
此文章同步發布於個人部落格,有興趣的大大也可以來參觀一下:D