Vue.js - 組件間溝通

學習用Vue設計網站要習慣把網站的內容物看成用組件堆疊而成的樂高城,把組件依照各自控管的邏輯劃分不但易於分工、容易維護且可以在不同的router下重複使用,呈現自己事先定義好的組件。

但是問題來了,如果兩個組件之間需要溝通(e.g.組件A需要參考組件B的資料來呈現給前端、組件A需要通知組件B某件任務處理完畢…等),要如何去實現呢?

父組件傳遞給子組件: Props

Props可以將父組件的資料傳遞給子組件,請參考以下範例。
(注意不要在組件中直接操作改變props的值,否則可能會因物件傳址發生難以監控的怪bug,最好是統一把改動data的邏輯交給父組件或是用vuex統一管理資料。)

父組件 (傳送)

此範例以v-for的方式把objList的每個物件透過prop(v-bind)傳遞給Child的obj(自行定義屬性名稱)

<div class="parent">
<Child
v-for="singleObj in objList"
:obj="singleObj"
:key="singleObj.key"
/>
</div>
import Child from '../components/Child' 

export default() {
components: {
Child
},
data() {
return {
objList:[
{ title: 'props', content: '父傳子' },
{ title: 'event emitter', content: '子傳父' },
{ title: 'event bus', content: '其他' }
]
}
}
}

子組件 (接收)

接收到的props可直接呈現給前端,或是依照它做一些CSS樣式的改變或格式的變化(filter, computed),但請千萬不要直接操作props。

<div class="child">
<div>${ obj.title }</div>
<div>${ obj.content }</div>
</div>
export default() {
props: {
obj: Object // 可事先定義變數的正確類型以利debug
}
}

子組件傳遞給父組件: event emitter

子組件 (傳送)

export default() {
methods: {
callParent(payload) {
// 第一個參數為事件名稱,第二個為傳遞過去之參數
this.$emit('callParent', payload)
}
}
}

父組件 (接收)

用v-on(@)監聽自訂義的事件(callParent)後執行callMe,可以透過$event傳參。

<div class="game-shop">
<GameCard
@callParent="callMe($event)"
/>
</div>
export default() {
methods: {
callMe(payload) {
// 做點手腳
}
}
}

其他事件傳遞: Event Bus

建立一個新實體bus來充當非父子關係組件之間的溝通橋梁,專案小或資料邏輯不複雜的時候這個方式還可以一試,但專案功能繁複時建議改用vuex統一管理資料的狀態。

// main.js, 或是考慮把bus獨立成一個js檔
export const bus = new Vue();

ComponentA (傳送)

import { bus } from '../main'

export default() {
methods: {
AtoB(payload) {
// 第一個參數為事件名稱,第二個為傳遞過去之參數
bus.$emit('AtoB', payload)
}
}
}

ComponentB (接收)

import { bus } from '../main'

export default() {
created() {
// 第一個參數為事件名稱,第二個為傳遞過來之參數
bus.$on('AtoB', (payload) => {
// 做點手腳
})
}
}

以上就是Vue最基本的組件溝通方式,下次有機會再介紹vuex的具體使用方法。

參考