手撕Vuex-模組化共享資料上

BNTang發表於2023-11-05

前言

好,經過上一篇的介紹,實現了 Vuex 當中的 actions 方法,接下來我們來實現 Vuex 當中的模組化共享資料(modules)。

modules 方法用於模組化共享資料,那麼什麼叫模組化共享資料呢?其實非常簡單。

過去我們將所有模組的資料都放到 state 中共享,例如:

我們有三個模組 首頁 / 個人中心 / 登入,那麼我們就會將這三個模組的資料都放到 state 中,但是這樣會導致命名匱乏的問題。

比如說首頁中需要共享name, 個人中心中也需要共享name / 登入中也需要共享name,並且這三個name的取值還不一樣, 那麼為了能把這三條資料放到同一個state中, 我們就必須指定不同的名稱, 例如:

state:{
    homeName: 'www',
    accountName: 'BNTang',
    loginName: 'top'
}

這樣就會導致命名匱乏的問題,而且如果我們的專案足夠大,那麼我們的 state 中就會有很多的資料,這樣就會導致我們的 state 中的資料非常多,而且不好管理。

為了解決這個問題,Vuex 就推出了模組化共享資料的方法,那麼什麼叫模組化共享資料呢?模組化共享資料就是將不同模組的資料放到不同的模組(state)中,這個就是模組化共享資料。

那麼模組化共享資料怎麼做呢,我們先不要管怎麼做,我們先來看看模組化共享資料的好處。

我們還是拿上面的例子來說,我們有三個模組 首頁 / 個人中心 / 登入,那麼我們就會將這三個模組的資料都放到 state 中,但是這樣會導致命名匱乏的問題。

好,到這裡我們已經知道了模組化共享資料的好處,我們先來用一下模組化共享資料。

我先不管三七二十一,我在 Store 物件的 store 中定義了一個全域性的資料 globalName 取值為 BNTang,

定義完畢之後呢,這個 globalName 代表著全域性的資料,那麼我們就可以在任何一個模組當中使用這個資料,那麼接下來怎麼辦,例如這個時候我有兩個模組分別是首頁與個人中心,這兩個模組中分別有一個 name 資料,這兩個 name 該如何做呢,好我先寫程式碼再來解釋。

let home = {
    state: {
        name: '首頁'
    },
    getters: {},
    mutations: {},
    actions: {}
}

如上的程式碼和 Store 中有一套相同的結構,這個物件中儲存著首頁的 name,儲存完畢了之後,還沒新增到 Store 中,那麼如何新增到 Store 中呢,其實很簡單,我們只需要在 Store 中的 modules 中新增這個模組就可以了。

modules: {
    home: home
}

如上程式碼的寫法就代表著,我們 Store 除了儲存了全域性的共享資料以外還儲存了首頁模組的共享資料,那麼我們的個人中心資料該如何做呢,其實也是一樣的(也是同一個世界,同一個夢想的),我們來寫一個個人中心的模組。

let account = {
    state: {
        name: '賬戶'
    },
    getters: {},
    mutations: {},
    actions: {}
}

然後將這個模組新增到 Store 中,方式和上面一樣。

modules: {
    home: home,
    account: account
}

好了,到這裡我們已經定義了全域性共享的資料,與各個模組的共享資料,我們儲存歸儲存,但是我們怎麼使用呢,我們來看看。

拿全域性共享的資料(隨機找一個元件展示資料即可):

<p>{{ this.$store.state.globalName }}</p>

拿首頁的共享資料(隨機找一個元件展示資料即可):

<p>{{ this.$store.state.home.name }}</p>

拿個人中心的共享資料(隨機找一個元件展示資料即可):

<p>{{ this.$store.state.account.name }}</p>

測試效果我不貼圖了本人親自測試過,有個 注意點,我們的 Nuex 還沒有實現模組化,所以在測試的時候記得將自己實現的 Nuex 註釋掉,開啟官方的 Vuex。

到這裡,我們的頁面就已經展示了全域性共享資料與模組化共享資料,完成了將不同模組的資料放到不同的模組(state)中,這個就是模組化共享資料。

模組化中 getters/mutations/actions 的使用

我們知道在 Store 當中,我們可以使用 getters/mutations/actions 這三個方法,那麼這三個方法在模組化當中是怎麼使用的呢,先看全域性的,在全域性 Store 分別在這三個方法中定義方法,如下:

getters: {
    getGlobalName(state) {
        return state.globalName + '111111';
    }
},
mutations: {
    changeGlobalName(state, payload) {
        state.globalName += payload;
    }
},
actions: {
    asyncChangeGlobalName({commit}, payload) {
        setTimeout(() => {
            commit('changeGlobalName', payload);
        }, 1000);
    }
},

內容非常的簡單,如果是從之前的文章一步一步跟著來的再看如上的程式碼基本上沒有什麼壓力(我這裡不做過多的解釋,因為前面講解的很細,不懂的可以回去翻看之前章節的介紹),然後我們在元件當中使用這三個方法,如下:

<template>
  <div class="hello">
    <p>{{ this.$store.state.globalName }}</p>
    <p>{{ this.$store.getters.getGlobalName }}</p>
    <button @click="globalFn1">同步操作</button>
    <button @click="globalFn2">非同步操作</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  methods: {
    globalFn1() {
      this.$store.commit('changeGlobalName', 10);
    },
    globalFn2() {
      this.$store.dispatch('asyncChangeGlobalName', 5);
    }
  }
}
</script>
<style scoped>
</style>

關於測試自行測試,這裡不做過多的解釋(執行專案,點選頁面上面的按鈕即可查詢效果)。

好了這裡我們已經知道了全域性的 getters/mutations/actions 的使用,那麼模組化當中的 getters/mutations/actions 的使用又是怎麼樣的呢,我們來看看。

我先不管三七二十一,我在 home 模組中的 getters/mutations/actions 中定義方法,如下:

首頁模組:

getters: {
    getHomeName(state) {
        return state.name + '222222';
    }
},
mutations: {
    changeHomeName(state, payload) {
        state.name += payload;
    }
},
actions: {
    asyncChangeHomeName({commit}, payload) {
        setTimeout(() => {
            commit('changeHomeName', payload);
        }, 1000);
    }
}

我這個時候想,我在全域性 Store 的 getters/mutations/actions 方法中定義了方法,可以和之前的方式一樣使用,那麼在模組中的 getters/mutations/actions 方法中定義了方法,我能不能和之前的方式一樣使用呢,我們來看看。

首先展示首頁模組中的 name, 如果這裡直接和之前一樣的寫法肯定是不能展示的,所以這裡我就要提到一個注意點:如果獲取的是模組中state共享的資料, 那麼需要加上模組的名稱

知道了這個注意點之後,我們的程式碼就可以改寫為如下的方式來展示模組中 store 儲存的資料,程式碼如下:

<p>{{ this.$store.state.home.name }}</p>

上面這一點是我們在使用模組化共享資料的時候需要注意的,與尋常的使用方式不同,需要加上模組的名稱。

那麼我們從 getters/mutations/actions 中獲取資料呢,如果獲取的是模組中getters共享的資料, 那麼不需要加上模組的名稱,程式碼如下:

<p>{{ this.$store.getters.getHomeName }}</p>

mutation 與 action 與使用全域性的方式一樣,不需要加上模組的名稱, 在頁面編寫兩個按鈕,一個是同步,一個是非同步,在分別實現下各個按鈕的點選事件即可, 程式碼如下:

新增按鈕:

<button @click="homeFn1">同步操作</button>
<button @click="homeFn2">非同步操作</button>

實現方法:

homeFn1() {
  this.$store.commit('changeHomeName', 10);
},
homeFn2() {
  this.$store.dispatch('asyncChangeHomeName', 5);
}

好了,我們首頁模組的 getters/mutations/actions 的使用程式碼編寫好了,我們趕緊趁熱來測試一下,看看我們的程式碼是否能夠正常的執行,開啟瀏覽器點選按鈕即可完成測試我這裡略過。

首頁模組的我們編寫完畢了,接著來編寫個人中心模組的 getters/mutations/actions 的使用,其實和首頁模組的 getters/mutations/actions 的使用是一樣的,我們來看看,為了節約時間,我直接貼程式碼:

個人中心模組:

let account = {
    state: {
        name: '賬戶'
    },
    getters: {
        getAccountName(state) {
            return state.name + '333333';
        }
    },
    mutations: {
        changeAccountName(state, payload) {
            state.name += payload;
        }
    },
    actions: {
        asyncChangeAccountName({commit}, payload) {
            setTimeout(() => {
                commit('changeAccountName', payload);
            }, 1000);
        }
    }
}

頁面展示:

<p>{{ this.$store.state.account.name }}</p>
<p>{{ this.$store.getters.getAccountName }}</p>
<button @click="accountFn1">同步操作</button>
<button @click="accountFn2">非同步操作</button>

實現方法:

accountFn1() {
  this.$store.commit('changeAccountName', 10);
},
accountFn2() {
  this.$store.dispatch('asyncChangeAccountName', 5);
}

好了,到這裡我們的模組化當中的 getters/mutations/actions 的使用就已經完成了。

其實除了在全域性的 Store 中新增子模組,子模組還可以新增模組,可以無限的這樣新增模組,例如我現在有一個登陸模組,我將登陸模組新增到 account 模組中,登陸模組的程式碼如下:

let login = {
    state: {
        name: '登入'
    },
    getters: {
        getLoginName(state) {
            return state.name + '333333';
        }
    },
    mutations: {
        changeLoginName(state, payload) {
            state.name += payload;
        }
    },
    actions: {
        asyncChangeLoginName({commit}, payload) {
            setTimeout(() => {
                commit('changeLoginName', payload);
            }, 1000);
        }
    }
}

然後將登陸模組新增到 account 模組中,程式碼如下:

modules: {
    login: login
}

然後我們在頁面中展示登陸模組的資料,程式碼如下:

<p>{{ this.$store.state.account.login.name }}</p>
<p>{{ this.$store.getters.getLoginName }}</p>

展示資料的注意點與之前一樣,需要加上模組的名稱,而 getters 就不需要加上模組的名稱,然後我們在頁面中呼叫登陸模組的 mutations/actions 的方法,程式碼如下:

首先是觸發按鈕:

<button @click="loginFn1">同步操作</button>
<button @click="loginFn2">非同步操作</button>

然後是實現方法:

loginFn1() {
  this.$store.commit('changeLoginName', 10);
},
loginFn2() {
  this.$store.dispatch('asyncChangeLoginName', 5);
}

好了,到這裡我們的模組化的使用就已經完成了,我們趕緊來測試一下,看看我們的程式碼是否能夠正常的執行,開啟瀏覽器點選按鈕即可完成測試我這裡略過。

相關文章