Vue 中非父子組件間的傳值

總線機制

非父子之間傳值,能夠採用發佈訂閱模式,這種模式在 Vue 中被稱爲總線機制,或者叫作Bus / 發佈訂閱模式 / 觀察者模式vue

<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的屬性。vuex

組件被掛載以前會執行mounted鉤子函數,因此能夠在mounted中對change事件進行監聽。框架

this.bus.$on()那邊會被執行兩次,緣由是什麼呢?由於在一個child組件裏面,觸發事件的時候,外面兩個child的組件都進行了同一個事件的監聽,因此兩個child的組件都會執行一遍this.bus.$on()異步

Vuex

兩個兄弟組件之間公共的父組件,那麼它們就無法經過一個公用的父組件來進行數據的中轉,要實現這兩個頁面組件的數據通訊應該怎麼辦呢?函數

vuex是 Vue 官方推薦的數據框架,在 Vue 的大型項目開發之中,Vue 只能承擔視圖層的內容,而當咱們涉及到大量數據傳遞的時候,每每都須要一個數據框架進行輔助,Vue 之中這個數據框架就是vuexthis

看上圖vuex指的是整個圖中虛線部分的內容。spa

vuex是什麼呢?當咱們的一個項目之中,好比說多個組件之間進行復雜的數據傳遞很困難的時候,若是能把這些公用的數據,放在一個公共的存儲空間去存儲,而後某一個組件改變了這個公共的數據,其餘的組件就能感知到,不就能夠了嗎。vuex的設計理念就是這樣的。prototype

回到上圖,右側虛線那塊的圖就是公用數據存儲區域,咱們能夠把這個區域理解成store倉庫,這個倉庫是由幾部分組成的:設計

  • State:它是幹嗎用的呢?咱們全部的公用數據都存放在State當中,那組件想要用公用的數據,直接去調用State就能夠了
  • Actions:有些時候想要改變State中的數據,可是不能讓組件直接改變State中的數據,必須走一個流程。這裏有一些異步操做,將這些異步操做放在Actions,或者一些複雜的同步操做(批量),也能夠放在Actions
  • Mutations:組件想要改變數據先去調用Actions,經過Actions去調用MutationsMutations中放的是一個個同步的修改State的方法

結論:只有經過Mutations才能改變State中公用數據的值,這一步也不是絕對的,有時候能夠略過Actions這一步,讓組件直接調用Mutations修改State中的數據。這裏須要注意的是組件調用Actions是經過Dispatch方法,而組件直接調用Actions或者Actions調用Mutations是經過Commit方法。code

其實它就是一個單向數據的改變流程。

具體看下代碼是怎麼實現的:

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 給刪除了。
}
相關文章
相關標籤/搜索