规范目录结构
Vuex 并不限制代码的结构,但它规定了一些需要遵守的规则,只要遵守以下规则,可以随意组织代码。
- 应用层级的状态应该集中到单个 store 对象中。
- 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
- 异步逻辑都应该封装到 action 里面。
但是,如果把整个store都放在index.js中是不合理的,所以需要拆分:
- 如果 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
- 对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。
下面是项目结构示例:
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块
拆分 store 文件
- state.js :保存所有数据,以对象的方式导出
export default { pathName: '', // 路由 currDbSource: {}, // 当前数据源 currJobData: {}, // 当前元数据 DbSource: [], // 所有数据源,供元数据界面下拉列表使用 selectJobMeta: {}, // 当前选择的元数据(搜索后点击的单条数据) specialSubject: [], // 专题数据(多条) duplicateJobMeta: {}, // 复制的数据 };
- mutations.js :保存所有方法,用来改变 state 的数据
// 保存当前菜单栏的路径 export const savePath = (state, pathName) => { state.pathName = pathName; }; // 保存当前点击的数据源 export const saveCurrDbSource = (state, currDbSource) => { state.currDbSource = currDbSource; }; // 保存当前点击的元数据 export const saveCurrJobData = (state, currJobData) => { state.currJobData = null; state.currJobData = currJobData; }; // 保存所有数据源 export const saveDbSource = (state, DbSource) => { state.DbSource = DbSource; }; // 保存搜索后选择的那一条元数据 export const saveSelectJobMeta = (state, selectJobMeta) => { state.selectJobMeta = selectJobMeta; }; // 保存搜索的那一类专题 export const saveSpecialSubject = (state, specialSubject) => { state.specialSubject = specialSubject; state.selectJobMeta = {}; }; // 保存复制的元数据(名称为空) export const saveDuplicateJobMeta = (state, duplicateJobMeta) => { state.duplicateJobMeta = duplicateJobMeta; };
- actions.js :暴露给用户使用,借此触发 mutations 中的方法,保存数据(可执行异步操作)
// 触发保存菜单栏的路径方法 export const savePath = ({ commit }, payload) => { commit('savePath', payload); }; // 触发获取当前点击的数据源方法 export const saveCurrDbSource = ({ commit }, payload) => { commit('saveCurrDbSource', payload); }; // 触发获取当前点击的元数据方法 export const saveCurrJobData = ({ commit }, payload) => { commit('saveCurrJobData', payload); }; // 触发获取所有数据源方法 export const saveDbSource = ({ commit }, payload) => { commit('saveDbSource', payload); }; // 触发保存搜索后选择单条元数据方法 export const saveSelectJobMeta = ({ commit }, payload) => { commit('saveSelectJobMeta', payload); }; // 触发保存搜索专题数据方法 export const saveSpecialSubject = ({ commit }, payload) => { commit('saveSpecialSubject', payload); }; // 触发保存复制元数据方法 export const saveDuplicateJobMeta = ({ commit }, payload) => { commit('saveDuplicateJobMeta', payload); };这里有 2 种方式:
// 方法一: export const saveDbSource = (context, payload) => { context.commit('saveDbSource', payload); }; // 方法二: export const saveDbSource = ({ commit }, payload) => { commit('saveDbSource', payload); }; // 一种是通过 context上下文用来触发事件,一种是直接通过commit, // 为了保存数据,都需要加第二个参数payload,不然保存到vuex的数据就是空值
- index.js:引入相应模块,暴露出 store,供 vue 注册后全局使用
import Vue from 'vue'; import Vuex from 'vuex'; import state from './state'; import * as actions from './actions'; import * as mutations from './mutations'; Vue.use(Vuex); export default new Vuex.Store({ state, actions, mutations });
- main.js 中引入 index.js
// 引入vuex-store import store from './store/index'; new Vue({ el: '#app', router, store, render: h => h(App) });
模块化
当项目庞大,状态非常多时,可以采用模块化管理模式。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态组件内调用模块 a 的状态:
this.$store.state.a而提交或者
dispatch某个方法和以前一样,会自动执行所有模块内的对应type的方法:this.$store.commit('editKey') this.$store.dispatch('aEditKey')
[ 模块化细节 ]
- 模块中
mutations和getters中的方法接受的第一个参数是自身局部模块内部的statemodels:{ a:{ state:{key:5}, mutations:{ editKey(state){ state.key = 9 } }, .... } }
getters中方法的第三个参数是根节点状态models:{ a:{ state:{key:5}, getters:{ getKeyCount(state,getter,rootState){ return rootState.key + state.key } }, .... } }
actions中方法获取局部模块状态是context.state,根节点状态是context.rootStatemodels:{ a:{ state:{key:5}, actions:{ aEidtKey(context){ if(context.state.key === context.rootState.key){ context.commit('editKey') } } }, .... } }