Vue 非父子傳值(兄弟傳值)
Vue 中非父子元件間的傳值
匯流排機制
非父子之間傳值,可以採用釋出訂閱模式,這種模式在 Vue 中被稱為匯流排機制,或者叫做Bus
/ 釋出訂閱模式 / 觀察者模式
<div id="root">
<child content="Dell"></child>
<child content="Lee"></child>
</div>
Vue.prototype.bus = new Vue() //掛載 bus 屬性
Vue.component('child', {
data(){
return {
selfContent: this.content
}
},
props: {
content:String
},
template: '<div @click="handleChildClick">{{selfContent}}</div>',
methods: {
handleChildClick() {
this.bus.$emit('change',this.selfContent) // 釋出
}
},
mounted(){
this.bus.$on('change',(msg)=>{ //訂閱,這裡會被執行兩次
this.selfContent = msg
})
}
})
let vm = new Vue({
el: '#root'
})
Vue.prototype.bus = new Vue()
這句話的意思是,在 Vue 的prototype
掛載了一個bus
屬性,這個屬性指向 Vue 的例項,只要我們之後呼叫 Vue 或者new Vue
時,每個元件都會有一個bus
屬性,因為以後不管是 Vue 的屬性還是 Vue 的例項,都是通過 Vue 來建立的,而我在 Vue 的prototype
上掛載了一個bus
的屬性。
元件被掛載之前會執行mounted
鉤子函式,所以可以在mounted
中對change
事件進行監聽。
this.bus.$on()
那邊會被執行兩次,原因是什麼呢?因為在一個child
元件裡面,觸發事件的時候,外面兩個child
child
的元件都會執行一遍this.bus.$on()
Vuex
兩個兄弟元件之間公共的父元件,那麼它們就沒法通過一個公用的父元件來進行資料的中轉,要實現這兩個頁面元件的資料通訊應該怎麼辦呢?
vuex
是 Vue 官方推薦的資料框架,在 Vue 的大型專案開發之中,Vue 只能承擔檢視層的內容,而當我們涉及到大量資料傳遞的時候,往往都需要一個數據框架進行輔助,Vue 之中這個資料框架就是vuex
看上圖vuex
指的是整個圖中虛線部分的內容。
那vuex
是什麼呢?當我們的一個專案之中,比如說多個元件之間進行復雜的資料傳遞很困難的時候,如果能把這些公用的資料,放在一個公共的儲存空間去儲存,然後某一個元件改變了這個公共的資料,其他的元件就能感知到,不就可以了嗎。vuex
回到上圖,右側虛線那塊的圖就是公用資料儲存區域,我們可以把這個區域理解成store
倉庫,這個倉庫是由幾部分組成的:
State
:它是幹嘛用的呢?我們所有的公用資料都存放在State
當中,那元件想要用公用的資料,直接去呼叫State
就可以了Actions
:有些時候想要改變State
中的資料,但是不能讓元件直接改變State
中的資料,必須走一個流程。這裡有一些非同步操作,將這些非同步操作放在Actions
,或者一些複雜的同步操作(批量),也可以放在Actions
中Mutations
:元件想要改變資料先去呼叫Actions
,通過Actions
去呼叫Mutations
,Mutations
中放的是一個個同步的修改State
的方法
結論:只有通過Mutations
才能改變State
中公用資料的值,這一步也不是絕對的,有時候可以略過Actions
這一步,讓元件直接呼叫Mutations
修改State
中的資料。這裡需要注意的是元件呼叫Actions
是通過Dispatch
方法,而元件直接呼叫Actions
或者Actions
呼叫Mutations
是通過Commit
方法。
其實它就是一個單向資料的改變流程。
具體看下程式碼是怎麼實現的:
export default new Vuex.store({
state: {
name: '天天'
},
actions: {
changeName (ctx, name) { //ctx 是上下文
ctx.commit('changeName', name) //通過 commit 呼叫 mutations 去改變 state,這個 changeName 可以自己隨便起名字保證和 mutations 中一樣即可
}
},
mutations: {
changeName (state, name) {
state.name = name
}
}
})
元件需要使用就可以直接這樣使用this.$store.state.name
當其他地方需要修改name
時,可以這樣寫
handleNameClick (name) {
this.$store.dispatch('changeName', name) //派發一個名字叫 changeName 的 Actions,並把 name 傳過去
}
這邊我在改變state
時沒有任何非同步操作,而且這個操作也非常簡單,這個時候元件其實沒有必要去呼叫Actions
做這個轉發,元件可以直接去呼叫mutations
。
handleNameClick (name) {
this.$store.commit('changeName', name) //派發一個名字叫 changeName 的 mutation,並把 name 傳遞過去。所以上面的 store 裡可以把 Actions 給刪除了。
}