詳解Vuex下Store的模塊化拆分實(shí)踐
前言
最近的項(xiàng)目用到了 vue.js + vuex + vue-router 全家桶,版本為 >2.0,在搞Store的時(shí)候發(fā)現(xiàn),圈子里大部分關(guān)于vuex的文章都是比較基礎(chǔ)的Demo搭建方式,很少有涉及到比較復(fù)雜的模塊化拆分的Store實(shí)踐,而且事實(shí)上也有朋友在實(shí)踐中問(wèn)到過(guò)這方面的內(nèi)容,vuex自身提供了模塊化的方式,因此在這里總結(jié)一下我自己在項(xiàng)目里的心得。
模塊化拆分
vue.js的項(xiàng)目文件結(jié)構(gòu)在這里就不說(shuō)了,大家可以通過(guò)vue-cli初始化項(xiàng)目,腳手架會(huì)為你搭建一個(gè)start項(xiàng)目的最佳實(shí)踐。
默認(rèn)你已經(jīng)搭架好了一個(gè)項(xiàng)目,而且需要建立或者已經(jīng)是一個(gè)復(fù)雜的Store,但是還沒(méi)有進(jìn)行模塊拆分,你可以嘗試對(duì)其進(jìn)行模塊拆分,當(dāng)然在一開(kāi)始你不必一定需要這么做。
1. 安裝Vuex,建立文件結(jié)構(gòu)
在項(xiàng)目根目錄下安裝vuex:
npm install vuex -S
安裝完畢后,在項(xiàng)目的src文件夾下新建一個(gè)store文件夾,并且分別在其中新建modules,actions,mutations,getters,constants子文件夾和一個(gè)index.js文件。
目錄結(jié)構(gòu)如下:
└─ demo/ ├── build/ ├── config/ ├── node_modules/ ├── src/ │ ├── assets/ │ ├── components/ │ ├── store/ │ │ ├── actions/ │ │ │ ├──aAction.js │ │ │ ├──bAction.js │ │ │ └──cAction.js │ │ ├── constants/ │ │ │ └── types.js │ │ ├── getters/ │ │ │ └── aGetter.js │ │ ├── modules/ │ │ │ ├── aModules.js │ │ │ ├── bModules.js │ │ │ ├── cModules.js │ │ │ └── index.js │ │ ├── mutations/ │ │ │ ├── aMutation.js │ │ │ ├── bMutation.js │ │ │ └── cMutation.js │ │ └── index.js │ ├── App.vue │ └── main.js ├── static/ ├── utils/ ├── test/ └── index.html
好了,基本的文件結(jié)構(gòu)大概就是上面?這樣的。
2. 編寫(xiě)模塊A
在編寫(xiě)模塊之前,首先設(shè)定一些type類(lèi),例如:
types.js
module.exports = keyMirror({
FETCH_LIST_REQUEST: null,
FETCH_LIST_SUCCESS: null,
FETCH_LISR_FAILURE: null
})
function keyMirror (obj) {
if (obj instanceof Object) {
var _obj = Object.assign({}, obj)
var _keyArray = Object.keys(obj)
_keyArray.forEach(key => _obj[key] = key)
return _obj
}
}
上面自己實(shí)現(xiàn)keyMirror的方法,大家也可以使用下面這個(gè)包:
https://github.com/STRML/keyMirror
keyMirror的作用就是下面這個(gè)一個(gè)形式?,作用其實(shí)也不是很大:
Input: {key1: null, key2: null}
Output: {key1: key1, key2: key2}
actions/aAction.js
import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'
export const fetchListAction = {
fetchList ({ commit, state }, param) {
commit(FETCH_LIST_REQUEST)
axios.get('http://youdomain.com/list')
.then(function (response) {
commit(FETCH_LIST_SUCCESS, {
data: response.data
})
console.log(response);
})
.catch(function (error) {
commit(FETCH_LIST_FAILURE, {
error: error
})
console.log(error);
});
}
}
getters/aGetter.js
export const = fetchListGetter = {
hotList (state) {
return state.list.data.slice(0, 10)
}
}
mutations/aMutation.js
import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
export const fetchListMutation = {
[FETCH_LIST_REQUEST] (state) {
state.isFetching = true
},
[FETCH_LIST_SUCCESS] (state, action) {
state.isFetching = false
state.data = action.data
state.lastUpdated = (new Date()).getTime()
},
[FETCH_LIST_FAILURE] (state, action) {
state.isFetching = false
state.error = action.error
}
}
modules/aModule.js
import { fetchListAction } from '../actions/aAction'
import { fetchListGetter } from '../getters/aGetter'
import { fetchListMutation } from '../mutations/aMutation'
export const list = {
state: {
isFetching: false,
data: []
}
actions: fetchListAction,
getters: fetchListGetter,
mutations: fetchListMutation
}
modules/index.js
import { list } from './aModule'
module.exports = {
list: list
}
3. 掛載store
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
import { list } from './modules'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
list: list
},
plugins: [createLogger()],
strict: process.env.NODE_ENV !== 'production'
})
if (module.hot) {
module.hot.accept(['./mutations'], () => {
const newMutations = require('./mutations').default
store.hotUpdate({
mutations: newMutations
})
})
}
export default store
4. store注入vue實(shí)例
main.js
····
import store from './store'
····
var vue = new Vue({
store,
····
})
vue.$mount('#app')
5. 在Component中使用
Vuex 提供了組件中使用的mapState,mapAction,mapGetter方法,因此可以很方便的調(diào)用。
Example.vue
<template>
·········
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
·······
methods: {
...mapActions([
'fetchList'
])
},
computed: {
...mapState{
list: state => state.list
},
...mapGetters{[
'hotList'
]}
}
}
</script>
<style>
·······
</style>
復(fù)用模塊
模塊化拆分之后可以實(shí)現(xiàn)較為復(fù)雜的數(shù)據(jù)流,特別地,如果對(duì)action和mutation稍加改造,就可以復(fù)用模塊:
比如我們?cè)贓xample.vue中發(fā)起Action:
Example.vue
<template>
·········
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
·······
mounted () {
this.fetchList({
request: 'week'
})
},
methods: {
...mapActions([
'fetchList'
])
},
computed: {
...mapState{
list: state => state.list
},
...mapGetters{[
'hotList'
]}
}
}
</script>
<style>
·······
</style>
在上面的例子中,我們?cè)诮M件掛載完成之后發(fā)起了一個(gè)fetchList的action,并添加了一個(gè)名為request的參數(shù),這里給一個(gè)week值,也可以給按照業(yè)務(wù)需要給month、year之類(lèi)的值,接下來(lái)對(duì)aAction.js做一些修改。
actions/aAction.js
import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'
export const fetchListAction = {
fetchList ({ commit, state }, param) {
commit(FETCH_LIST_REQUEST, {
request: param['request']
})
axios.get(`http://youdomain.com/${param['request']}list`)
.then(function (response) {
commit(FETCH_LIST_SUCCESS, {
request: param['request']
data: response.data
})
console.log(response);
})
.catch(function (error) {
commit(FETCH_LIST_FAILURE, {
request: param['request']
error: error
})
console.log(error);
});
}
}
請(qǐng)求成功之后,在 commit()中加入了一個(gè)request的參數(shù),這樣Mutation就可以從里面獲取相應(yīng)的參數(shù),最后對(duì)aMutation做一些修改。
mutations/aMutation.js
import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
export const fetchListMutation = {
[FETCH_LIST_REQUEST] (state, action) {
state[action.request].isFetching = true
},
[FETCH_LIST_SUCCESS] (state, action) {
state[action.request].isFetching = false
state[action.request].data = action.data
state[action.request].lastUpdated = (new Date()).getTime()
},
[FETCH_LIST_FAILURE] (state, action) {
state[action.request].isFetching = false
state[action.request].error = action.error
}
}
state加入了[action.request],以區(qū)分不同的接口數(shù)據(jù)。
完成以上修改后,只需要在組件調(diào)用相應(yīng)的action時(shí)加入不同的參數(shù),就可以調(diào)用相同類(lèi)型但數(shù)據(jù)不同的接口。
總結(jié)
以上是我在Vuex實(shí)踐中總結(jié)的一些東西,分享給大家,如果有不合理或者錯(cuò)誤❌的地方,也希望各位老司機(jī)不吝賜教,有機(jī)會(huì)多交流。也希望大家多多支持腳本之家。
微信號(hào):pasturn
Github:https://github.com/pasturn
相關(guān)文章
vue項(xiàng)目中Eslint校驗(yàn)代碼報(bào)錯(cuò)的解決方案
這篇文章主要介紹了vue項(xiàng)目中Eslint校驗(yàn)代碼報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
vue $mount 和 el的區(qū)別說(shuō)明
這篇文章主要介紹了vue $mount 和 el的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
vue使用window.open()跳轉(zhuǎn)頁(yè)面的代碼案例
這篇文章主要介紹了vue中對(duì)window.openner的使用,vue使用window.open()跳轉(zhuǎn)頁(yè)面的代碼案例,本文通過(guò)實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下2022-11-11
vue 自定義提示框(Toast)組件的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue 自定義提示框(Toast)組件的實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
vue基礎(chǔ)知識(shí)--axios合并請(qǐng)求和slot
這篇文章主要介紹了vue中的axios和slot,文中代碼非常詳細(xì),對(duì)大家的工作學(xué)習(xí)有所幫助,感興趣的朋友可以參考下2020-06-06

