Vuex简介:
    Vuex是一个专门为Vue.js应用程序开发的状态管理模式
        它采用集中存储管理应用组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化;
        Vuex也集成到Vue的官方调试工具Devtools,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能
如果我们不使用Vuex,那么就需要定义全局变量,但定义的全局变量不在vue的响应式系统中,我们还需要给其设置相应,很复杂,所以就有了Vuex
设置全局变量:

const shareObj = {
name:'pshdhx'
}
Vue.prototype.shareObj = shareObj;

这样不是响应式的;
那么Vue管理什么状态呢?
    在开发中,往往会遇到多个状态,在多个界面之间共享的问题;
    比如用户的登录状态,用户名称,头像,地理位置信息等;
    比如商城的收藏,购物车中的物品;
这些状态信息,我们都可以放在统一的地方,对其进行保存和管理,而且他们还是响应式的;
1、首选对Vue项目引入Vuex的包
    npm install vuex --save
2、初步建立Vuex的目录结构
    在src文件夹下新建index.js
3、在index.js中引入注册使用vuex

import Vue from 'vue'
import Vuex from 'vuex'
//安装vuex
Vue.use(Vuex);
//创建对象
const store = new Vuex.Store({
state:{},
mutations:{},
getters:{},
actions:{},
modules:{}
})
//导出store对象
export default store

4、在main.js中注册

import store from '/store'
new Vue({
el:'#app',
store,
render:h=>h(App)
})

初使用vuex-State,Mutations

Vuex的初使用_异步请求

state是存储状态变量的部分,如果想要对其进行修改,那么必须要经过Mutations(存储同步请求方法的模块),这样用Devtools插件才能够看到state中值的变化 ,方便遇到错误时调试;如果直接进行修改state中的值,那么Devtools里边的状态变量不会进行响应,只会在页面上进行响应,造成页面上的值与Devtools中的值不一致的后果,影响开发人员判断;

为什么绕一圈,才能修改state中的值,因为Actions中定义的是异步方法,Mutations中定义的是同步方法,不同的方法调用方式不同,但是最终都是通过调用Mutations中的方法进而修改State中的值;

初步使用vuex-state模块
index.js
const store = new Vuex.Store({
state:{
count:100
},
mutations:{
increment(state){
state.count++
},
decrement(state){
state.count--
}
}
})
App.vue
<button @click="addition">+</button>
<button @click="subtration">-</button>
<script>
methods:{
addition(){
this.$store.commit('increment')
},
subtration(){
this.$store.commit('decrement')
}
}
</script>

Vuex的核心概念

State,Getters,Mutations,Actions,Modules

State的单一状态

  我们知道,在国内我们有很多信息需要被记录,比如上学时的个人档案,工作后的社保记录,公积金记录等;

  这些信息被分散在很多地方进行管理,有一天当你需要办理户口迁入的时候,你会发现你需要到各个对应的工作地点去打印、盖章各种资料信息,最后到一个地方提交证明你的信息无误;

而单一的状态管理就避免了这种情况,所以所有的状态变量都放在了State中进行管理;

Getters基本使用

const store = new Vuex.Store({
State:{
students:[
{id:110,name:'pshdhx1',age:18},
{id:111,name:'psdhhx2',age:20},
{id:112,name:'pshdhx3',age:22},
{id:113,name:'pshdhx4',age:25},
]
}
})

此时我们要过滤出age>20的对象;

computed:{
moreThan20(){
return this.$Store.state.students.filter(age=>age>=20).length;
}
}
//如果是这样,那么在每个页面中都要定义该计算方法,但是如果定义在vuex中,那么就很方便了;
getters:{
moreThan20(state){
return state.students.filter(s => s.age>20).length;
}
}
//getters中方法的参数中有state,就是index.js中的state
实际上getters中可以返回函数
moreAgeStu(state){
return function(age){
return state.students.filter(s=>s.age>age)
}
// return age => {return state.students.filter(s=>s.age>age)}
}
//App.vue
<button @click="this.$store.getters.moreAgeStu(20)"></button>

Mutations状态更新

Vuex的store状态更新的唯一方式:提交mutation

Mutation主要包含两部分:

  字符串的事件类型:type

  一个回调函数handler,该回调函数的第一个参数就是state

Mutations的定义方式
mutations:{
state.count++
}
通过mutation进行更新
increment:function(){
this.$store.commit('increment');
}
App.vue
methods:{
addCount(count){
this.$store.commit('incremntCount',count);
}
}
mutations:{
incrementCount(state,count){
state.counter+=count
}
}
methods:{
addStudent(){
count stu = {id:114,name:'pshdhx5',age:'23'}
this.$store.commit('addStudent',stu);
}
}
addCount(count){
this.$store.commit({
type:'incrementCount',
count
});
}
//这时传递的是count对象;
Mutations:{
incrementCount(state,payload){
state.counter+=payload.count
}
}
state:{
info:{
name:'pshdhx6',
age:40,
height:170
}
}

这些属性加入到了响应式系统中,而响应式系统会监听属性的变化。当属性变化时,会通知所有界面中用到该属性的地方,让界面刷新;

updateInfo(state){
state.info.name='pshdhx7' //因为name在info中原本就要,所以会响应式改变;包括Devtools
state.info['address']= '洛杉矶' //因为info中原本没有,所以Devtools不会添加此变量
}

这时需要加入到

Vue.set(state.info,'address','洛杉矶'); //这时变量就添加到了Devtools中
updateInfo(state){
//该方法做不到响应式
delete state.info.age
//该方法可以做到响应式
Vue.delete(state.info,'age')
}

如果在Mutations中使用了异步请求,那么Devtools中的变量将不会得到响应;

所以要将异步请求加入到Actions中

actions:{
aUpdateInfo(){
//context:上下文
setTimeout(()=>{
context.commit('updateInfo')
},1000)
}
}

这时在App.vue中要这样调用Actions中的方法

methods:{
updateInof(){
//this.$store.dispatch('aupdateInfo');
this.$store.dispatch('aupdateinfo','我是payload');
//为了可以获得异步请求的调用结果
this.$store.dispatch('aupdateInfo',()=>{
console.log('异步请求已经调用完成')
})

//也可以这样写:
this.$store.dispatch('aupdateInfo',{
payload:'我是携带的信息',
success:()=>{
console.log('异步请求已经调用完成');
}
})
}
}

在Actions中我们这样写:

actions:{
aupdateInfo(context,payload){
setTimeout(()=>{
context.commit('updateInfo');
console.log(payload.message);
payload.success();
},1000)
}
}

//或者用promise这样写
actions:{
aupdateInfo(context,payload){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
context.commit('updateInfo')
console.log(payload);
resolve('11111');
},1000)
})
}
}

因为用了在actions中用了promise,这样可以咋app.vue中调用then回调函数

this.$store.dispatch('aupdateInfo','我是携带的信息').then(res=>{
console.log('里面完成了提交');
console.log(res);
})

初使用Modules

module是模块的意思,为什么在Vuex中要使用模块呢?

Vue使用单一状态树,那么也就意味着很多状态都会交给Vuex来管理;

当应用变得非常复杂时,store对象就有可能变得非常臃肿;

为了解决这个问题,Vuex允许我们将store分割成模块Module,而每个模块拥有自己的state,mutations,actions,getters等;

const moduleA = {
state:{},
mutations:{},
actions:{},
getters:{}
},
const moduleB = {
state:{},
mutations:{},
actions:{},
getters:{}
},
const store = new Vuex.Store({
modules:{
a:moduleA,
b:moduleB
}
})

store.state.a //->moduleA的状态
store.state.b //->moduleB的状态

Vuex的初使用_响应式_02

moduleA就是state中的一个对象;

我们可以这样使用:

{{this.$store.state.a.name}}
const moduleA = {
state:{
name:'pshdhx A'
},
mutations:{
updateName(state,payload){
state.name = payload
}
},
actions:{},
getters:{
fullName(state){
return state.name+'1111'
},
fullNames(state,getters){
return getters.fullName+'2222'
},
funllName3(state,getters,rootState){
return getters.fullName2+rootState.counter
}
}
}

App.vue

methods:{
updateName(){
this.$store.commit('updateName','lisi');
}
}

<h2>{{$store.getters.fullName}}</h2>
const moduleA = {
state:{
name:'zhangsan'
},
mutations:{
updateName(state,payload){
state.name = payload
}
},
actions:{
aupdateName(context){
setTimeout(()=>{
context.commit('updateName','wangwu');
},1000)
}
}
}

App.vue
methods:{
asyncUpdateName(){
this.$store.dispatch('aupdateName');
}
}

dispatch对象

Vuex的初使用_异步请求_03

actions的写法

const moduleA = {
actions:{
increment({state,commit,rootState}){
if((state.count+rootState.count)%2===1){
commit('increment')
}
}
}
}

如果getters中也需要使用全局的状态,可以接受更多的参数

const moduleA = {
getters:{
withRootCount(state,getters,rootState){
return state.count = rootState.count
}
}
}

vuex的项目结构

Vuex的初使用_响应式_04

引入文件的时候注意:

如果是export的是default,那么可以直接import .. from '..';
如果不是,那么需要import {...} from '..';


import mutations from './mutations'
import actions from './actions'
import getters from './getters'

const store = new Vuex.Store({
state,
mutations,
actions,
getters
})