一、什么是vuex module,為什么要使用vuex模塊化?
模塊化,就是將vuex分為不同的模塊,無論從項目上還是結構上,都容易維護,我們在平時寫的vuex中,都是在一個文件中,寫state、getters、mutations、actions。想象一下,如果我們的項目特別大,比如淘寶那么大,那么我們vuex中要維護的內容會特別多的時候,例如“購物車”需要用到vuex,“設置”需要用到vuex,“首頁”也需要用到vuex,那么如果我們都寫到一個文件中,就會出現代碼相當的“臃腫”。這一個store文件最后好幾萬行代碼。還怎么維護?
所以,我們vue官網就給出了辦法,使用vuex模塊化開發。
今天我們簡單學習使用,學會后,你要查閱官網,深入學習,才能提高這個技術。
模塊化有很多寫法,今天按照我的習慣,簡單的寫一下,我們和以前一樣,需要下載vuex,會得到一個store文件夾,內部我們有一個index跟文件。並且,我們需要自己創建一個modules文件夾,里邊放入我們想要區分的js模塊文件,你想分成多少個模塊,就分成多少個,我目前寫了倆個模塊,一個是購物車car.js,一個是我的my.js,type.js先不用管。如圖:
首先我們需要先將modules中的所有文件引入到index.js根文件中(以前我們是導出mutations等方法,現在這個文件中,我只引入了模塊,所以只需要導出模塊),如下(index.js):
import Vue from "vue"; import Vuex from "vuex"; // 引入兩個模塊文件 import car from './modules/car'; import my from './modules/my'; Vue.use(Vuex); export default new Vuex.Store({ modules: { car, my } });
然后我們就可以在每個模塊當中,寫入獨立的state、mutations等等。這樣我們在使用的時候,購物車就用car.js;我的就用my.js。用購物車car.js舉例(其他文件同理),如下(car.js):
const state = { } const getters = { } const mutations = { } const actions = { } export default { namespaced: true, state, getters, mutations, actions }
這里就可以像以前一樣寫我們的vuex方法了。細心的同學會注意到,我們導出時,會多出一個namespaced:true,一般我們在模塊使用時,都會加入這個屬性。
命名空間:namesapced:true,當模塊被注冊后,它的所有getter、action及mutation都會自動根據模塊注冊的路徑調整命名,也就是說,我們在調用這些方法時,需要加上這個文件的路徑(比如我要訪問這個文件中的state里邊的某個屬性:this.$store.state.car。后邊這個car就是多了個car.js模塊名,因為如果不加模塊名,那我們會訪問所有模塊中的屬性,那就亂了),所以我們要加上命名空間,相當於獨立的區塊去使用,模塊和模塊之間互不干擾。
和平時一樣,我們跟個案例:
點擊增加數值(car.js):
const state = { number: 100 } const getters = { } const mutations = { add(){ state.number ++; } } const actions = { } export default { namespaced: true, state, getters, mutations, actions }
我們重點說一下vue中怎么獲取模塊中的內容。我們可以和平常一樣,直接用this.$store.state.car.number來獲取到state中的number內容。我們今天說說在項目中最常使用的:輔助函數mapState、mapGetters、mapActions和mapMutations。
不一一舉例,簡單說兩個mapState和mapActions,深入理解可去看官網。
我們在使用時,需要先引入:
import { mapState, mapActions } from 'vuex';
這兩個函數,前者寫在計算屬性computed中,后者寫在方法methods中。
在寫入時,需要用到展開符...,它可以將內容一一的展開。
舉個例子:
let a = [1, 2, 3]; let b = [4, 5, 6]; let c = [...a, ...b]; console.log(c); // [1, 2, 3, 4, 5, 6]
那我們獲取一下state中的number:
computed: { ...mapState({ a: state => state.car.number }) }, methods: { ...mapMutations(['car/add']), add(){ this['car/add']() // 注意,這里this后沒有點 } },
展開mapState,定義一個a,然后返回state中的car模塊下的number常量。展開mapMutations,返回是個數組,數組中是個字符串,返回car模塊下的add方法,定義一個add,直接觸發就可以。有人會問,觸發mutations中的方法不是應該用commit嗎,答案是我們用了mapMutations,它會將這個路徑直接映射成commit方法,所以我們直接用就行,這也是與原來的區別。
我們定義的這個a,就是想要的數值,可以在標簽中展示出來,add也直接使用。
<h2>{{a}}</h2> <button @click="add">點擊增加</button>
這樣寫出來,是好用的,但是看起來會有問題。想一下,car是個模塊,我們現在只是舉例而已,但是如果我們在開發中,這個模塊下命名空間比較深入,還有其他模塊,一層一層比較多,就會變成這個樣子:
computed: { ...mapState({ a: state => state.car.xx.xx.xx.number // 如果下邊還有很多,就要寫很多重復的 car.xx.xx.xx,如: b: state => state.car.xx.xx.xx.name c: state => state.car.xx.xx.xx.key }) }, methods: { ...mapMutations(['car/xx/xx/xx/add']), add () { this['car/xx/xx/xx/add']() } }
這個層層的嵌套,那就要寫很多重復的car/xx/xx/xx,所以我們可以,將這個模塊當作字符串提取出來,換個寫法,按照我們的舉例:
computed: { ...mapState('car', { a: state => state.number }) }, methods: { ...mapMutations('car', ['add']), },
如上所示,我們可以將他作為參數,放到前面,這樣所有綁定都會自動將該模塊作為上下文,寫出來也簡單不少。當然我們還可以再簡化一些。我們可以通過使用createNamesapcedHelpers創建基於某個命名空間輔助函數。它返回一個對象,對象里有新的綁定在給定命名空間值上的組件綁定輔助函數。
就是我們可以從vuex中引入createNamespacedHelpers,然后將剛才的字符串作為參數,傳進來,如下:
// 這里引入createNamespacedHelpers import { createNamespacedHelpers } from 'vuex'; // 定義mapState、mapMutations,並將car傳入createNamespacedHelpers const { mapState, mapMutations } = createNamespacedHelpers('car'); computed: { ...mapState({ a: state => state.number }) }, methods: { ...mapMutations(['add']), },
這就是vuex模塊化,寫法都很多,看我們自己的習慣,當然了,我們在模塊中,還可以使用常量替代Mutation事件類型。在多人開發時,我們知道mutations中放入了方法,如果有很多方法,多人協作時找起來會比較麻煩,那我們可以創建一個放入常量的文件(前文中我們創建的type.js文件),在里邊我們可以定義常量,但注意的是,我們開發中習慣常量要大寫,單詞之間用下划線分開。並且,在模塊中引入這個文件:
一、首先,我們創建一個js文件,我們前文圖片中的type.js,在里邊創建一個常量,開發時前后要一致,並加以標注:
// 前后都要大寫,一般前后名稱一致,但是為了我們能夠理解,本次我們寫兩個 // 開發中,我們應該這樣寫:export const ADD_NUMBER = 'ADD_NUMBER' // 本次我們定義前后不一樣的 export const ADD_NUMBER = 'AAA' // 點擊增加數字
二、在car模塊中引入type.js並使用引入進來的常量:// 按需引入常量import { ADD_NUMBER } from './type';
const state = { number: 100 } const getters = { } const mutations = { // 使用常量命名,注意,這里[ADD_NUMBER]映射出來的名稱,其實是AAA // 我們寫成固定的數字,也可以設置參數、靈活傳參 // 第一個參數是state,第二個參數是傳入參數payload [ADD_NUMBER](state, payload){ state.number += payload; } } const actions = { } export default { namespaced: true, state, getters, mutations, actions }
三、vue頁面,由於剛才我們用了payload參數,所以我們也需要傳入參數,然后我們可以思考下,我們觸發的名稱應該寫哪一個?
methods: { // 思考一下問號的地方,應該寫 ADD_NUMBER還是AAA? ...mapMutations(['AAA']), },
這個問題也就是我剛才故意在常量中,前后不一樣的原因,由於我們前后都寫一樣,有些小白會不知道,這里定義的到底是前邊的名稱,還是后邊字符串的名稱。答案是AAA,也是ES6中對象的擴展寫法。
最后的寫法是這樣的:
<h2>{{a}}</h2> <button @click="aaa(2)">點擊增加</button> computed: { ...mapState({ a: state => state.number }) }, methods: { // 思考一下問號的地方,應該寫 ADD_NUMBER還是AAA? // ...mapMutations(['AAA']), // 我們除了可以寫成數組,還可以用對象的寫法 ...mapMutations({ aaa: 'AAA' }) // 你可以按照原始寫法寫,當然要去掉標簽中的參數,參數改成下邊傳遞。 // aaa(){ // this.$store.commit('car/AAA', 100); // } },
這就是modules模塊化的開發寫法,希望看完,你們會有所收獲。