Vuex的元素对象
Vue中的元素
Vue中的元素都是对象,共有【5】个,分别为:
1. state:
1. state对象用于保存变量的对象
2. Vuex提出了state单一状态树(或单一数据源)的概念,即Single Source of Truth,
其思想就是将所有需要保存用来共享的信息存放在同一个state里面
示例:
// state对象中可以存储任意的数据类型 state:{ counter: 1000, students: [ {name: 'Carrey', age: 18, city: 'Xiangyang'}, {name: 'Jack', age: 25, city: 'Shenzhen'}, {name: 'John', age: 22, city: 'Chongqing'}, {name: 'Jackie', age: 20, city: 'Guangzhou'}, {name: 'Jean', age: 19, city: 'Beijing'} ], infor: { name: 'Jakie', age: 18, hieght: 1.88 } },
2. getters:
1. getters类似于组件中的计算属性,其格式也是通过函数返回一个值
2. getters中用来存储state中的数据变异后的状态
3. 比如,state中存储着学生信息,则getters中可以返回年龄大于20岁的学生等等,做一些筛选的工作
4. getters中的计算属性可以传入getters对象,从而使用已经定义好的计算属性
示例:
getters:{ // 1. 获取学生年龄大于20的学生 age20more(state){ return state.students.filter(s => s.age > 20); }, // 2. 返回年龄大于20的学生的人数,这里调用了年龄大于20的学生的计算属性 age20moreLen(state, getters){ return getters.age20more.length; }, // 3. 返回年龄大于给定值的学生 // 这里是通过返回一个函数来实现,被调用时会传入一个实参,该计算属性是将学生年龄与这个传入实参进行比较 ageMoreValue(state){ return function(age){ return state.students.filter(s => s.age > age); }; }, },
3. mutations:
1. mutations中用来存储各种方法,这些方法可以用来存储各种操作state变量的方法
2. Vuex中的store状态的唯一更新方式:体骄傲mutations
3. mutations主要包括两部分:
字符串的事件类型(type)
一个回调函数(hander),该回调函数的第一个参数是state
4. mutation更新数据时,可以进行传参给mutations中的方法,被传入的参数成为mutation的载荷(payload)
5. mutation的传参风格:
addNum(num){ // 普通传参 // this.$store.commit('incrementNum', num); // 对象传参 this.$store.commit({ type: 'incrementNum', num, }); } // 传参风格导致接受数据不同 incrementNum(state, num){ // 普通传参时,接收到的num就是传入的那个变量 console.log(num); // 打印出num的值 // 对象传参时,接收到的时传入的那个对象(其实也很好理解,传入什么就接受到什么) console.log(num); // 打印出对象{type: "incrementNum", num: 传入的num的值} }
示例:
// mutation的定义方式: mutations:{ // 1. 定义counter加1操作 increment(state){ state.counter++; }, // 2. 定义counter减1操作 decrement(state){ state.counter--; }, // 3. 定义counter加指定数的操作 incrementNum(state, Num){ state.counter+=Num; } }, // 通过mutation更新state 在需要更新state的页面提交对应的指令即可 // 1. 调用普通函数 add(){ this.$store.commit('increment') } // 2. 调用时给函数传参 addNum(num){ this.$store.commit('incrementNum', num); }
mutations相关补充:
Vuex的响应式原理
1. Vuex中存储在store时响应式的,存储在state中的变量会被监视,一旦数据发生改变Vue组件会自动更新
2. 但是,只有提前在store中存储的变量才是响应式的,通过事件操作新增上去的变量不是响应式的
如:通过事件操作以下指令
updataInfor(state){
state.infor['address'] = 'Chongqing';
delete state.infor.height;
}
// 这两种方法只能改变数据,不会更新到页面上
3. 但是Vue组件可以解决上述两种问题,实现新增变量和删除变量的响应式
updataInfor(state){
Vue.set(state.infor, 'address', 'Chongqing');
Vue.delete(state.infor, 'height');
}
// 这两种方法可以实现响应式操作
mutation的常量类型
1. 这是用来避免我们在页面中请求mutation的方法时发送的方法名和仓库里面的函数名对不上(因为很容易敲错)
2. 思想:页面中发送去请求的那个方法名与仓库里面二点函数名设置为一样的名字,并且设置为一个字符串常量
3. 为什么这样可以避免变量名敲错呢
因为导入的模块,使用时会有代码提示的嘛
4. 实现步骤:
1. 新建一个mutation-types.js的模块
2. 在该模块中,设置字符串常量并导出
export const INCREMENT = 'increment';
3. 在仓库中引入上面创建的mutation-types.js模块,宁且将仓库中mutation里的函数名修改为引入的常量名
import * as types from './mutation-types'
将:
increment(state){
state.counter++;
},
修改为:
[types.INCREMENT](state){
state.counter++;
},
4. 将对应界面上的js代码区域引入上面常见的mutation-types.js模块,并将发送的指令修改为引入的常量名
import * as types from './store/mutation-types'
将:
add(){
this.$store.commit(increment);
},
修改为
add(){
this.$store.commit(types.INCREMENT);
},
4. actions
1. 在mutation中定义的方法必须式同步方法
2. 这是因为我们使用的devtools时,这个工具可以帮我们捕捉mutation的快照,
3. 单如果是异步操作,devtools工具追踪不到这个操作什么时候完成的
如:在mutation中定义的异步方法
updataInfor(state){ setTimeout(() => { state.infor['height'] = 'Chongqing'; }, 1000) }
// 这种方法调用时,会导致页面有更新,但是devtools工具中追踪的相关变量值没有改变
4. 倘若我们必须在仓库中定义一些异步操作的方法,则需要借助于action对象,在该对象中定义异步操作方法
5. 思路:在action中定义一步操作,去发送mutation指令,还是利用mutation方法去操作state变量
具体操作:
1. 在action对象中定义需要的异步操作方法,发送请求道响应的mutation方法,通过mutation方法去修改数据
actions:{ // context 上下文,会根据所处环境不同而有不同的指向,类似于this // action中默认有一个context变量,在action中context指的就是仓库store aUpdataInfor(context){ setTimeout(() => { context.commit('updataInfor'); // 该指令发送给mutation中的方法 }, 1000) } },
2. 在需要的页面中,发送action请求
// 注意,这里的发送指令变成了dispatch
updataInfor(){ this.$store.dispatch('aUpdataInfor'); }
异步操作时,需要在操作完成时,告诉调用的对象我已经完成了
此时需要将一步操作结果返回来
实现步骤:
1. 在action对象中的异步操作中,返回一个Promise对象
actions:{ aUpdataInfor(context, payload){ console.log(payload); // 打印出传进来的值 // 返回一个Promise对象 return new Promise((resolve, reject) => { setTimeout(() => { context.commit('updataInfor'); console.log('请求成功了'); resolve('11111'); // 异步操作成功时返回结果 }, 1000) }) } },
2. 则在响应页面中调用action方法时,得到的就是一个Promise对象,
可以直接在调用的指令后添加.then()来获取返回值,并进行进一步操作
updataInfor(){ this.$store.dispatch('aUpdataInfor', '我是传过去的数据').then((res) => { console.log(res) }); // 由于this.$store.dispatch('aUpdataInfor', '我是传过去的数据') // 指令发送后,返回来的是一个Promise对象,因此后面可以直接跟.then() }
5. modules
1. module就是模块的意思,当项目中的state, mutations, actions, getters中的元素太多事就会显得很臃肿
2. 为了解决这个问题,Vuex允许将state, mutations, actions, getters进行分模块管理
3. 实现形式
module:{ a:{ state:{ // state中的变量名可以和其他模块中的变量名重复,只不过引用时,需要使用$store.state.a.name // 这是因为,实际上模块中的state会被加载到主模块的state中 name:'Tom', phone:'HUAWEI' }, mutations:{ // 这里传入的state是该模块中的state, // 这里的mutations方法名不得与其他的名重复 // 引用时直接引用即可(和主模块中的引用没区别) updataName(state, payload){ state.name = payload; } }, getters:{ // 引用时与主模块中的getters引用无区别,直接引用即可{{$store.getters.fullName}} fullName(state){ return state.name + '123'; }, // 这里传入的getters是指本模块的getters fullName2(state, getters){ return getters.fullName + state.name; }, // 这里传入的rootState是指主模块(或根模块)的整个对象 fullName3(state, getters,rootState){ console.log(rootState); return getters.fullName2 + rootState.counter; }, }, actions:{ aUpdata(context, payload){ setTimeout(() => { context.commit('updataName', payload); }, 1000) } }, }, b:{ state:{}, mutations:{}, actions:{}, getters:{} }, ...... }
4. 引用模块中定义的对象中的值