1. 程式人生 > 實用技巧 >Vue 非父子傳值(兄弟傳值)

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去呼叫MutationsMutations中放的是一個個同步的修改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 給刪除了。
}