1.创建项目并安装vuex
1 2
| npm create project_name npm i vuex --save # 也可在创建project_name时进行选择安装
|
安装后需要进行配置配置:
2.状态管理的流程

当我们去修改Vuex 中的 State的时候,我们不应该直接去修改 State ,而是通过 Actions、Mutations 进而来修改State。
Devtools:它是Vue开发的一个浏览器插件,通过Mutations,它可以记录我们每一次修改State。
Actions:如果我们请求是异步操作的话,我们会通过Actions,将异步转化为同步,因为Devtools通过Mutations来监听我们对 State 的修改只能是同步操作。如果请求是同步的话,我们可以绕过Actions。
3.state
state里存放需要共享的变量,每个vue组件都可以通过访问$store.satate来访问共享数据
在index.js中的state定义共享变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({ state: { counter:100, }, mutations: { }, actions: { }, modules: { } })
|
在所有的vue组件中都能使用这个共享变量counter
helloworld.vue中
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div class="hello"> <h1>{{ $store.state.counter }}</h1> </div> </template>
<script>
export default { name: 'HelloWorld', } </script>
|
app.vue中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <template> <div id="app"> <h1>{{ $store.state.counter }}</h1> <HelloWorld/> </div> </template>
<script> import HelloWorld from './components/HelloWorld.vue'
export default { name: 'App', components: { HelloWorld } } </script>
|
4.getters
有时候我们并不需要访问的state中的所有数据,或者希望它进行加工后得到的数据,就可以使用getter,它的功能类似于computed
<h1>{{ this.$store.getters.powerCounter }}</h1>
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({ state: { counter:100, }, getters: { powerCounter(state){ return state.counter * state.counter }, fun1: function (state,getters){ return 0 }, fun1: function (state,geters){ return function(param1){ return 1 } } }, mutations: { }, actions: {
}, modules: { } })
|
5.mutation
state中的共享变量的更改必须通过mutation中的定义methods(理解为事件)进行,这样DevTools才能跟踪修改,便于开发调试。
而调用mutation中的方法是通过this.$store.commit(“method_name”)进行的
index.js中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({ state: { counter:100, }, mutations: { increment(state){ state.counter++ }, decrement(state){ state.counter-- }, decrementWithPayload(state,param){ }, decrementInAnotherStyle(state,payload){ }, }, actions: { }, modules: { } })
|
app.vue中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <template> <div id="app"> <h1>{{ counter }}</h1> <button @click="increment()">+</button> <button @click="decrement()">-</button> <HelloWorld/> </div> </template>
<script> import HelloWorld from './components/HelloWorld.vue'
export default { name: 'App', computed:{ counter:function (){ return this.$store.state.counter } }, components: { HelloWorld }, methods:{ increment(){ this.$store.commit("increment") }, decrement(){ this.$store.commit("decrement") }, //提交mutation事件时,也可带上参数,多个参数时需要封装称对象传入 decrementWithPayload(param){ this.$store.commit("decrement",param) }, //另一种提交风格,此时mutation中第二个参数接收的是一个对象 decrementInAnotherStyle(param){ this.$store.commit({ type:"decrement", param, //es6语法 }) }, } } </script>
|
mutation响应更新,在旧版本中使用的是watcher,也就是它只会对state中原有的数据进行监听和响应,新加入的对象属性是不会响应更新的,需要使用Vue.set(state.obj,”objAttr”,attrVal)或Vue.delete(state.obj,”objAttr”)等方式,而新版的vue中默认都会进行响应更新。
在开发过程中,因为commit时提交的是事件名,字符串形式容易出现拼写错误,所以会使用常量来代替事件名
6.action
当需要在mutation中进行异步操作时,state中的数据是不会实时动态刷新的。此时需要把异步操作放在action中进行,然后再action中调用mutation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script> export default { name: 'App', methods:{ doSomeAsync(){ this.$store.dispatch("actionName") this.$store.dispatch("actionNameWithPayload",payload) this.$store.dispatch("actionUsePromise",payload).then(function(res){ //do something after finish async } }) }, } } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| mutations: { mutationName(state){ state.counter++ }, mutationWithPayload(state){ state.counter++ }, }, actions: { actionName(context){ setTimeout(function(){ context.commit("mutationName") },3000) }, actionNameWithPayload(context,payload){ setTimeout(function(){ context.commit("mutationWithPayload",payload) },3000) }, actionUsePromise(context,payload){ return new Promise(function (resolve,reject){ setTimeout(function(){ context.commit("mutationWithPayload",payload) resolve(payload) },3000) }) } },
|
当需要不同的action之间需按一定顺序执行时,就可以封装为promise的形式
还可以把组件中的方法映射到action中,详细见官网mapActions使用,类似的还有mapGetters
7.modules
当store中的内容很多时,不便于管理维护,可以划分子模块,每个模块是一个独立的store,它们包含再根store中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use(Vuex)
const moduleA={ state: { valA:100, }, getters: { getValA(state,getters,rootState){ return state.valA* state.valA } }, mutations: { mutationName(state){ state.counter++ }, }, actions: { actionName(context){ setTimeout(function(){ context.commit("mutationName") },3000) }, }, } export default new Vuex.Store({ state: { }, getters: { }, mutations: { }, actions: { }, modules: { moduleA:moduleA } })
|
8.结构划分
可以把index.js中的代码进行抽取划分到多个文件中,便于开发维护。
把文件抽离为如下结构

index.js就变成了如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import Vue from 'vue' import Vuex from 'vuex' import moduleA from "./modules/moduleA"; import getters from "./getters"; import actions from "./actions"; import mutations from "./mutations"; Vue.use(Vuex)
const state = { counter:1, } export default new Vuex.Store({ state, getters, mutations, actions, modules: { moduleA:moduleA } })
|