npm install vuex --save-dev //安装vuex
// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.store({
state:{
},
mutation:{
},
action:{
},
getter:{
},
module:{
}
})
export default store
// main.js
import store from './store'
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
Vuex.store需要传入的各个属性:
state
state封装Vuex需要管理的状态;
单一状态树(不建议new两个或以上的store)。
//例子:
const store = new Vuex.store({
state:{
counter:1000
},
...
})
//访问state中的状态
{{ $store.state.counter }}
//修改state中的状态
"$store.state.counter++" //不建议直接修改,直接修改尽管也是响应式的,
//但是这样的修改方式无法被devtools追踪到,不便于后期的调试
//那么应该怎样修改?
首先看一幅图:
这是官方建议的修改方式,我们从最下方的紫色的State开始看起,State借由Render可以在Vue Components上进行展示,而Vue Components需要通过分配Actions,然后commit到Mutations,最后通过Mutations的Mutate行为来修改State。
可以看到,在Mutations处向外延伸连接到了一个Devtools,这是一个Vue官方的浏览器插件,它的作用正是追踪修改,保存修改记录的。
那么为什么不直接从Vue Components指向Mutations呢?为什么还要再多走一步Actions呢?
这里要区分清楚,其实从Vue Components指向Mutations也是可以的,只是这样的修改方式只适用于同步操作,如果是异步操作的话,就必须要经过Actions,否则的话Devtools将追踪不到异步操作的记录。
从图中可以清楚的看到,Actions通过Backend API将异步操作转换为同步操作,之后再传入到Mutations,这样就能被Devtools追踪到了。
需要注意的是,Devtools是一个浏览器插件,使用之前需要先在浏览器上安装。
所以如果是同步操作的话,正确的修改方式是:
const store = new Vuex.store({
state:{ //定义状态
counter:1000
},
mutations:{ //定义方法
increment(state){ //默认参数state
state.counter++
},
decrement(state){
state.counter--
}
},
...
})
this.$store.commit('incremnet') //通过这种方法调用mutations中定义的方法
this.$store.commit('decremnet')
getters
getters类似于一个计算属性,当我们需要获取state中的一些变异数据,并且这种数据多个组件都需要用到时,推荐使用getters。
const store = new Vuex.store({
state:{
counter:1000
students:[
{id:100,name:'Jack'},
{id:101,name:'Tom'},
{id:102,name:'Jane'}
]
},
getters:{
getPowercounter(state){ //默认第一个参数为state
return state.counter * state.counter
},
getIdgt101(state){ //获取id大于101的学生
return state.students.filter(s => s.id > 101)
},
getIdgt101Length(state,getter){ //获取id大于101的学生的数量,这里可传入第二个默认参数getters
return getter.getIdgt101.length
},
getIds(state){ //获取id大于指定id的学生,不能在这里传入id,第二个参数传入的不管是什么都被指向getters
return id => {
return state.students.filter(s => s.id > id)
}
}
}
...
})
$store.getters.getIdgt101 //调用getter中的方法
$store.getters.getIds(100)
mutations
Vuex官方指定,对状态的更改必须要经过mutations,这里要注意区分getters与mutations,getters是对状态的异变但这种异变不会作用于state中,即状态本身是没有改变的,只是呈现出来的变了,而mutations是改变了state中的状态。
mutations:{
increment(state){ //默认传入state参数
},
increment(state,count){ //需要传入其它参数时,放在后面
},
increment(state,obj){ //传入多个参数时,以对象的形式放在state后面
}
}
//调用
//风格1
$store.mutations.commit('increment')
$store.mutations.commit('increment',count)
$store.mutations.commit('increment',obj)
//风格2
$store.mutations.commit({
type:'increment',
count //注意这里的count传入mutations中的increment()方法后是作为对象形式传入的,即应该payload.count这样访问
})
Vuex的响应式注意点
Vuex中管理的状态都是响应式的,但这要有一个前提条件,即这些状态是提前已经定义的,是已经初始化过的并封装在state中的,比如说:
state:{
info:{name:'lihua',age:18}
}
这个info当然是响应式的,我们对info中的数据即name和age不管做什么更改都会立即呈现在页面上,但如果我们想要往info中添加一个新属性,你就会发现,属性虽然在后台确实添加进了info中,但它不是响应式的,这是因为新属性并没有事先被定义,所以它不会被添加到Vue的响应式系统中。
那么这时,我们又确实希望这种行为也能是响应式的,那么该怎么办呢?
方法如下:
Vue.set(state.info,grade,2018) //响应式的添加一个新属性
Vue.delete(state.info,name) //响应式的删除一个属性
actions
如果是同步操作,那么直接经由mutations修改状态就可以,但如果是异步操作,之前已经提到,需要先经过actions的一层包装之后,再经由muations修改状态,否则devtools将追踪不到异步操作。
具体用法参考如下:
mutations:{
updateinfo(state):{
state.info.name = 'xiaoming'
}
},
actions:{
unpadeInfo(context){ //这里也有默认参数,但是context,不是state,context相当于store
setTimeout(() => {
context.commit('updateinfo') //这里commit的是mutations中的方法
},1000)
}
}
//调用
$store.actions.dispatch('updateInfo')
需要传入参数时,参照:
mutations:{
updateinfo(state):{
state.info.name = 'xiaoming'
}
},
actions:{
unpadeInfo(context,payload){ //定义第二个参数接受传入的参数,对象类型
setTimeout(() => {
context.commit('updateinfo')
... //操作payload
},1000)
}
}
$store.actions.dispatch('updateInfo',message) //在这里传入参数
另外,因为actions中封装了一步方法,当我们需要在异步方法中定义回调时,参考如下:
mutations:{
updateinfo(state):{
state.info.name = 'xiaoming'
}
},
actions:{
unpadeInfo(context,payload){
return new Promise((resolve,reject) => {
setTimeout(() => {
context.commit('updateinfo')
... //操作payload
resolve() //调用resolve
},1000)
})
}
}
$store.dispatch('updateInfo',message)
.then(() => {
... //回调函数
})
modules
modules的作用是给Vuex分块,当Vuex管理的状态过多而导致代码或者逻辑混乱时,我们可以在modules中定义新的模块,这些模块与store类似但作为store的一部分,如下:
const store = new Vuex.store({
state:{},
mutations:{},
actions:{},
getters:{},
modules:[
VuexA:{ //VueA模块
state:{},
mutations:{},
actions:{},
getters:{},
},
VuexB:{
...
},
...
}
})
//访问Vuex中的state
$store.state.Vuex.***
//对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。