vuex的基本用法> 直接上代码,一眼飘过
jsimport Vue from 'vue';import Vuex from 'vuex'; Vue.use(Vuex); let state = { count: 6,} let getters = { countResult(state){ return '统计结果为' + state.count; }} let actions = { incrementYB({commit,state}){ // 异步,比如发请求后再commit setTimeout(() => { commit('incrementTB'); }, 1000) }} let mutations = { incrementTB(state){ state.count++; }} export default function createVuexStore(){ return new Vuex.Store({ state, actions, mutations, getters, });}
> 当然,我们真正项目中不会这样写,肯定拆成一个个文件模块,然后引入来使用,另外,我们还会将变量抽成一个文件types.js(下文会讲),方便统一管理。 # vuex的模块化管理> 如果我们按照上述写法来管理状态,那么代码将显得格外臃肿。 所以,我们可以根据下图的思路进行模块管理。
>根据上面的图片,将每个模块的state、action和mutation根据模块进行划分,其实,
getters也可以根据模块来划分,但是考虑到getters类似于计算属性computed,可能会去计算多个模块之间的状态,所以也可以将
getters不做模块化,统一管理。 ## vuex模块化目录结构
jsvuexStore | ---------modules | | | --------user.js | ---------getters.js | ---------types.js | ---------index.js
## 模块化状态文件>根据第一张图,我们将state、action和mutation进行模块划分,那么对于用户模块的state、action和mutation如何划分呢?内容vuexStore/modules/user.js如下:
jsimport { ADD_USER, GET_AVG_AGE } from '../types.js';const user = { namespaced: true, state: { count: 5, userList: [ {id:0, name: 'yuhua0', age: 10}, {id:1, name: 'yuhua1', age: 11}, {id:2, name: 'yuhua2', age: 12}, {id:3, name: 'yuhua3', age: 13}, {id:4, name: 'yuhua4', age: 14}, ] }, mutations: { [GET_AVG_AGE](state){ return state.userList.reduce((pre, next) => { return pre + next.age }, 0)/state.userList.length; }, [ADD_USER](state, playload){ state.userList.push(playload); state.count++; } }, actions: { addUserAsync({commit}, playload){ setTimeout(() => { commit(ADD_USER, playload); }, 1000) } }} export default user;
- state、actions和mutations的用法,几乎跟非模块化一样,只不过是放在了user对象中。- namespaced这个字段为true,表示开启命名空间,这代表着你要使用该文件内的数据时,数据都在该命名空间下,那这个命名空间是什么呢?index.js中的modules下的key就是命名空间(下文会讲)。这其实是vuex模块化的关键一步。- 另外,我们在该文件开头导入了types.js文件,以及将变量使用在了mutations和actions中,这个types.js其实是为了统一管理提交数据的动作。types.js不需要做模块化,这样能让开发者一看就知道存在哪些提交数据的操作。 ## types.js 提交类型管理> 我们知道,改变store中数据状态的唯一方法就是提交commit,所以,我们可以所有的commit动作用一个文件types.js统一管理,这样让我们看起来一目了然。同时,如果需要改变提交动作的名称,也只要在这个文件内统一修改就可以了。
jsexport const ADD_USER = 'ADD_USER';export const GET_AVG_AGE = 'GET_AVG_AGE';
## getters.js 统一管理> 上面已经说明,getters是可以放入module中模块化管理的,但也可以统一管理,原因是我们对数据进行计算时,数据可能是来自多个模块的。
jslet getters = { userList: state => state.users.userList, userCount: state => state.users.count,} export default getters;
## 入口文件管理> 有了模块中的state、mutation、actions和外部的getters,以及types,我们可以将他们一起收口,导入入口文件index.js中:
jsimport Vue from 'vue';import Vuex from 'vuex'; Vue.use(Vuex); // 模块导入import users from './modules/user' // getters导入import getters from './getters.js'; export default function createVuexStore(){ return new Vuex.Store({ modules: { users, }, getters, });}
# vuex模块化的使用## 普通使用方法>上面已经将vuex模块化结构搭建完毕,下面我们来看看如何使用模块化的vuex - 获取state数据:store.state.模块化命名空间.count - 获取getter数据: store.getters.userList - 注意:如果你的getter是模块化的,那你获取数据也是store.getters.userList,因为会自动合并在一起 - 提交mutations: store.commit(“模块化命名空间/mutation方法名”, playload) - 提交actions: store.dispatch(“模块化命名空间/actions方法名”, playload)- 假设我们有用户模块:user.vue
vue<template> <div> <h4 style="display:inline-block;">{{$store.state.users.count}}</h4> <ul> <li v-for="user in $store.getters.userList" :key="user.id"> {{user.name}}今年{{user.age}}岁了 </li> </ul> <button @click="addUser">同步提交数据</button> <button @click="addUserAsync">异步提交数据</button> </div></template> <script>import { ADD_USER, GET_AVG_AGE } from '../vuexStore/types.js'export default { methods: { addUser(){ this.$store.commit("users/" + ADD_USER, {name: 'yuhuahuayu', age: 5}) }, addUserAsync(){ this.$store.dispatch("users/addUserAsync", {name: 'yuhuahuayuAsync', age: 6}) } }}</script>
## 辅助函数使用方法> 感谢vuex为我们提供了非常渐变的辅助函数使用方法,能够更快捷的达到上面的效果- mapGetters: 写在computed中
js computed: { ...mapGetters(['userCount']), }
- 注意:getters不需要传参,mapGetters的参数写成数组- mapState: 写在computed中
js computed: { ...mapState({ userList: state => state.users.userList, count: state => state.users.count, }) }
- 参数携程对象的形式- mapMutations: 写在methods中,有两种写法: - 没有payload载荷:
js methods: { ...mapMutations(['提交动作0', '提交动作1']), }
> 因为写在methods中,所以按照method的调用方法调用,比如:
html <button @click="提交动作0">确定</button>
- 有payload载荷:
js methods: { ...mapMutations({ addUser: `users/${ADD_USER}`, }) }
> 这样的话,我们如果要派发
users/${ADD_USER}
动作,就只需要调用addUser即可,有payload载荷的话,在调用addUser方法时传入,比如:
html <button @click="addUser({name: 'yuhua', age: 6})">确定</button>
- mapActions: 写在methods中,也是两种方法,与mapMutations一样,在此不做赘述。如果不明白,可以看下面的示例:
vue<template> <div> {{'来自Getters的Count' + userCount}} <h4 style="display:inline-block;">{{count}}</h4> <ul> <li v-for="user in userList" :key="user.id"> {{user.name}}今年{{user.age}}岁了 </li> </ul> <button @click="addUser({name: 'yuhuahuayu', age: 5})">同步提交数据</button> <button @click="addUserAsync({name: 'yuhuahuayuAsync', age: 6})">异步提交数据</button> </div></template> <script>import { ADD_USER, GET_AVG_AGE } from '../vuexStore/types.js'import { mapGetters, mapState, mapMutations, mapActions } from 'vuex';export default { methods: { ...mapMutations({ addUser: `users/${ADD_USER}`, }), ...mapActions({ addUserAsync: `users/addUserAsync`, }) }, computed: { ...mapState({ userList: state => state.users.userList, count: state => state.users.count, }), ...mapGetters(['userCount']) }}</script>
# 老项目vuex的模块化改造> 一个项目的开发并不难,难的是对古老的项目的改造,当然,在改造过程中,往往不是难,更多的是烦… > 那么,对于老项目的vuex如何尽可能少改动原有代码下去改造成模块化的vuex? ## 保持老数据不变> 老数据一般是下面这样的,或者对下面的数据做了文件拆分,然后导入进来
jsimport Vue from 'vue';import Vuex from 'vuex'; Vue.use(Vuex); let state = { count: 6,} let getters = { countResult(state){ return '统计结果为' + state.count; }} let actions = { incrementYB({commit,state}){ // 异步,比如发请求后再commit setTimeout(() => { commit('incrementTB'); }, 1000) }} let mutations = { incrementTB(state){ state.count++; }} export default function createVuexStore(){ return new Vuex.Store({ state, actions, mutations, getters, });}
- OK,咱们对这部分保持不变,那么当新的模块开发的时候,先将当前老数据的getters,移到getters.js文件中(原本就有的就不用变了)。- 然后,创建modules,比如开发users模块,如下:
js... // 模块导入import users from './modules/user' // getters导入import getters from './getters.js'; export default function createVuexStore(){ return new Vuex.Store({ modules: { users, }, getters, state, actions, mutations, });}
- 接着在创建modules/user.js,内容与上文的modules/user.js一致(当前文件结构目录:vuex的模块化管理>模块化状态文件)。- 然后创建types.js,将新模块的commit的动作,都抽离到types.js中 # 老项目vuex的模块化改造后的使用- 对于vuex中的老数据,使用就按照正常的使用方法,即: - state: store.state.count - getter: store.getters.getUserList - mutation: store.commit(‘addUser’, {name: ‘yuhua’, age: 18}) - action: store.dispatch(‘addUserAsync’, {name: ‘yuhua’, age: 18})- 对于vuex的心数据,就按照上述所讲的模块化使用方法来使用。> 其实,这种写法,就是对新老数据管理的兼容。