安装和使用
import Vuex from 'Vuex'
Vuex
Vuex是一种状态管理模式,它集中式的管理应用所有组件的状态
- 一个简单的vuex实例包含了以下部分
- state,驱动应用的数据源
- view,以声明的方式将数据映射到视图
- action,响应在view上的用户输入导致的状态变化
开始
- 和全局对象有以下两点不同
- Vuex的状态存储响应式的
- 不能直接改变
store
中的状态
- 该方式直接使用script标签引入vue和vuex
const store = new Vuex.Store({
state:{
count: 0
},
mutations: {
increment (state) {
state.count++;
}
}
});
store.commit('increment');
console.log(store.state.count);
计数实例
<div id="app">
<p>{{ count }}</p>
<p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</p>
</div>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
})
new Vue({
el: '#app',
computed: {
count () {
return store.state.count
}
},
methods: {
increment () {
store.commit('increment')
},
decrement () {
store.commit('decrement')
}
}
})
State
- 有以下特征
- 单一状态树
- 一般通过vue实例中的计算属性返回state中的数据
- 为了从根组件注入到每一个子组件,可以在vue实例中,使用store选项引入store。同时,在子组件中使用
this.$store
获取
// vue实例中
const app = new Vue({
el: '#app',
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
// 子组件中
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
mapState
如果,每个state中数据都需要定义,太麻烦。可以使用mapState方法
// 一定要引入该方法
import { mapState } from 'vuex'
// 当state中数据不用改变的时候,使用字符串数组
export default {
computed: mapState(['count','else']);
}
// 当state中数据需要改变的时候,使用对象
export default {
computed: mapState({
count: state => state.count,
countAlias: 'count',
allCount (state) {
return this.localCount + state.count
}
});
}
// 项目中使用,组件中
export default {
computed: {
...mapState({
compComputedA: SET_AIR,
compComputedB: SER_LAND
}),
compComputedC: SER_SKY
}
}
对象展开运算符
通常情况下,vue组件不仅需要定义自己的计算属性,同时要用计算属性承接state中的各个数据。
export default {
computed: {
...mapState({
}),
comp1 () {
}
}
}
组件依旧保留局部性
有些严格属于组件的数据,依旧应该保存为组件数据
getters
其实某个state数据中,在多个组件中被修改,但是被修改的逻辑是相同。可以通过下边的这种方式,进行复用
- 其实Vuex中的getters就像是computed,计算属性,使用方式也相同
- getters中方法的参数
- 第一个参数是state
- 第二个参数是getters,这样可以访问getters中其他方法
// Vuex
Vuex.Store({
state: {
count: 1
},
// 相当于根据state进行一定的修改,但不是直接修改!!!!
getters: {
allCompCount (state) {
return state.count + 1;
}
}
});
// 子组件
Vue.component('my-comp',{
template: '<p></p>',
computed: {
myComp () {
return this.$store.getters.allCompCount
}
}
});
mapGetters 辅助函数
该函数的功能,是将store上的getters映射到子组件上
Mutations
只有Mutations能够改变state中的数据
- 提交荷载
payload
- 整个参数使用含有type的对象
- Mutations需要遵守的响应式规则
- 所有根级state数据,需要在Vuex中定义好
- 使用
Vue.set(obj,key,val)
添加或者设置对象属性 - 或者使用
var newObject = {...oldObject,newPro:newVal}
- 使用常量代替Mutations代替事件类型,可以使
linter
工具发挥作用
- 具体使用,参考Vuex,不是很了解
- Mutations 必须是同步函数
- 在组件中提交
Mutations
- 该方法的参数,可以是字符串数组
- 可以是对象
// 这个是定义
mutations: {
increment: function (state) {
// 默认参数
}
}
// 下面都是使用
// 单个荷载
state.commit('increment',10);
// 多个荷载
state.commit('increment',{
count: 10,
all: 100
});
// 整个使用含有 type 的对象传递
state.commit({
type: 'increment',
count: 10,
all: 100
});
// 在子组件中提交 Mutations
import { mapMutations } from 'vuex'
methods: {
...mapMutations({
add: 'increment'
}),
elseMethods
}
Actions
Actions解决了Mutations不能执行异步函数的问题
- Actions有以下特性
- Actions提交的是Mutations,不是直接改变state
- Actions可以执行任何异步操作
- Actions中没每个方法都可以接受一个参数
context
,该参数不是store,但是通过它可以访问store的属性和方法。该参数通常使用对象解构的方式接受
context.state
context.getters
context.commit
context.dispatch
- 分发Actions
store.dispatch('increment')
- 支持对象和荷载的方式分发
- 组件中分发Actions
- 和Mutations在组件中分发的方式相同
// 对象参数分发
store.dispatch({
type: 'increment',
count: 10
});
// 荷载方式分发
store.dispatch('increment',{
count: 10
});
组合Actions
如何知道Actions的异步执行完毕?如何在其他Actions中使用?
- 异步执行的Actions,需要返回一个Promise对象
- 在其他地方调用
- 结合
async/await
,暂时不知道
// 异步执行的Actions应该的定义方式
// 返回的Promise对象,记得要在完成的时候将状态标记为resolve
Actions: {
actionA ({ commit }) {
return new Promise(function(resolve,reject){
setTimeOut(()=>{
commit('increment');
resolve();
},100);
});
}
}
// 在其他地方调用
store.dispatch('actionA').then(()=>{
});
// 在其他Actions中使用
Actions: {
actionA ({ dispatch }) {
dispatch('actionA').then(()=>}{
});
}
}
Modules
由于store可能过于庞大,因此,允许使用模块的方式来定义
Modules 的基础使用
var moduleA = {
state: {},
mutations: {},
actions: {}
}
var moduleB = {
state: {},
mutation: {},
actions: {}
}
var store = new Vuex.Store({
modules: {
moduleA,
moduleB
}
});
// !!!! 注意,使用的时候模块名称是在后边的
store.state.moduleA
Modules 的局部状态
由于局部性,在模块中的参数,有所增加。从此,可以看出context不是store
// 模块中的各个方法的参数
getters: {
g (state,getters,rootState) {}
}
mutations: {
m (state,payload) {}
}
actions: {
a ({state,rootState,commit,getters,dispatch}) {}
}
命名空间
通过
namespace:true
定义该模块使用命名空间
- 使用命名空间的模块,在外部访问的时候需要添加上命名空间
// 定义
modules: {
moduleA: {
accout: {
namespace: true,
state: {},
mutations: {},
getters: {},
actions: {}
}
}
}
store.commit('account/m');
store.dispatch('account/a');
// 选用getters的方式不同
store.getters['account/g']; // 使用的是中括号
// 项目中,有命名空间,但是没有用`spacename:true`,反而将 路径 赋值给一个常量
//
export default {
methods: {
...mapMutations({
m01: 'CAMERA/SET_CAMERA',
m02: SET_CAMERA
})
}
}
在命名空间中访问全局内容更
modules: {
moduleA: {
namespace: true,
state: {},
mutations: {},
getters: {
g (state,getters,rootState,rootGetters) {
getters.someOtherGetter // -> 'moduleA/someOtherGetter'
rootGetters.someOtherGetter // -> 'someOtherGetter'
}
},
actions: {
a ({ dispatch, commit, getters, rootGetters }) {
getters.someGetter // -> 'foo/someGetter'
rootGetters.someGetter // -> 'someGetter'
dispatch('someOtherAction') // -> 'foo/someOtherAction'
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
commit('someMutation') // -> 'foo/someMutation'
commit('someMutation', null, { root: true }) // -> 'someMutation'
}
}
}
}
带命名空间的绑定函数
参数使用对象的方式,比较麻烦,可以使用负载的方式
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo',
'bar'
])
}
总结
- Store中五个选项
- State
- Getters
- Mutations
- Actions
- Modules
- 中间的四个有map函数,map的作用是将store中的
State
映射到局部计算属性(需要再声明函数使用),Getters
映射到局部计算属性中,Mutations
映射到局部方法中,Actions
映射到局部方法中,这样才能够在组件中使用 - state通过
store.state
或者this.$store.state
使用