最近的項目用到了 vue.js + vuex + vue-router 全家桶,版本爲 >2.0,在搞Store的時候發現,圈子裏大部分關於vuex的文章都是比較基礎的Demo搭建方式,不多有涉及到比較複雜的模塊化拆分的Store實踐,並且事實上也有朋友在實踐中問到過這方面的內容,vuex自身提供了模塊化的方式,所以在這裏總結一下我本身在項目裏的心得。html
vue.js的項目文件結構在這裏就不說了,你們能夠經過vue-cli
初始化項目,腳手架會爲你搭建一個start項目的最佳實踐。vue
默認你已經搭架好了一個項目,並且須要創建或者已是一個複雜的Store,可是尚未進行模塊拆分,你能夠嘗試對其進行模塊拆分,固然在一開始你沒必要必定須要這麼作。node
在項目根目錄下安裝vuex:ios
npm install vuex -S
安裝完畢後,在項目的src
文件夾下新建一個store
文件夾,而且分別在其中新建modules
,actions
,mutations
,getters
,constants
子文件夾和一個index.js
文件。git
目錄結構以下:github
└─ 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
好了,基本的文件結構大概就是上面?這樣的。vue-router
在編寫模塊以前,首先設定一些type類,例如:vuex
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 } }
上面?本身實現keyMirror的方法,你們也可使用下面這個包:
github.com/STRML/keyMirrorvue-cli
keyMirror的做用就是下面這個一個形式?,做用其實也不是很大:npm
Input: {key1: null, key2: null}
Output: {key1: key1, key2: key2}
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); }); } }
export const = fetchListGetter = { hotList (state) { return state.list.data.slice(0, 10) } }
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 } }
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 }
import { list } from './aModule' module.exports = { list: list }
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
···· import store from './store' ···· var vue = new Vue({ store, ···· }) vue.$mount('#app')
Vuex 提供了組件中使用的mapState
,mapAction
,mapGetter
方法,所以能夠很方便的調用。
<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>
模塊化拆分以後能夠實現較爲複雜的數據流,特別地,若是對action和mutation稍加改造,就能夠複用模塊:
好比咱們在Example.vue中發起Action:
<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>
在上面的例子中,咱們在組件掛載完成以後發起了一個fetchList的action,並添加了一個名爲request
的參數,這裏給一個week
值,也能夠給按照業務須要給month
、year
之類的值,接下來對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); }); } }
請求成功以後,在 commit()中加入了一個request的參數,這樣Mutation就能夠從裏面獲取相應的參數,最後對aMutation作一些修改。
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],以區分不一樣的接口數據。
完成以上修改後,只須要在組件調用相應的action時加入不一樣的參數,就能夠調用相同類型但數據不一樣的接口。
以上是我在Vuex實踐中總結的一些東西,分享給你們,若是有不合理或者錯誤❌的地方,也但願各位老司機不吝賜教??,有機會多交流。
微信號:pasturn
Github:https://github.com/pasturn