vuex是一个专门为vue.js设计的集中式状态管理架构。状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。
(就是一种向各个组件可以传参的方式)

1. 准备

用脚手架搭建一个项目
安装vuex
npm install vuex --save

新建文件夹store,并在此文件夹下新建store.js文件。项目目录,如下:
这里写图片描述

  1. main.js添加
	//引入vuex文件
	import store from './store/store.js'//注意文件路径
  1. store文件夹下的store.js
	//引入我们的vue和vuex。
	import Vue from 'vue'
	import Vuex from 'vuex'
	//使用我们vuex,引入之后用Vue.use进行引用
	Vue.use(Vuex);

2.开始demo

准备工作完成后,我们只使用helloworld.vue和store.js文件

  1. 在helloworld.vue文件中,直接更改
	    <template>
        <div>
            <h2>{{msg}}</h2>
            <hr/>
            <h3>{{$store.state.count}}</h3>
            <div>
                <button @click="$store.commit('add')">+</button>
                <button @click="$store.commit('reduce')">-</button>
            </div>
        </div>
    </template>
    <script>
        export default{
            data(){
                return{
                    msg:'Hello Vuex',
                }
            }
        }
    </script>

2.store.js文件中添加

	const state = {
	   count:1
	}
	
	const mutations={
	    add(state){
	        state.count+=1;
	    },
	    reduce(state){
	        state.count-=1;
	    }
	}
	export default new Vuex.Store({
	    state,mutations
	});

完成页面,点击按钮可以+1或-1
这里写图片描述

3. state访问状态对象

学习状态对象赋值给内部对象,也就是把stroe.js中的值,赋值给我们模板里data中的值。

  • 通过computed的计算属性直接赋值
<h3>{{count}}</h3>
	computed:{
             count(){
                 return this.$store.state.count;
             }
         },
 这里需要注意的是 return this.$store.state.count这一句,一定要this,要不你会找不到$store的.
  • 通过mapState的对象/数组来赋值
	<h3>{{count}}</h3>
    <h3>{{countAlias}}</h3>
    <h3>{{countPlusLocalState}}</h3>
import {mapState} from 'vuex';//用import引入mapState。
computed: mapState({
   // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.msg
    }
})

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。

computed:mapState(["count"])

4. getters计算过滤操作

getters从表面是获得的意思,可以把他看作在获取数据之前进行的一种再编辑,相当于对数据的一个过滤和加工。你可以把它看作store.js的计算属性。

比如我们现在要对store.js文件中的count进行一个计算属性的操作,就是在它输出前,给它加上100.我们首先要在store.js里用const声明我们的getters属性。

//store.js
getters: {
    getcount: state => {
        return state.count += 100;
    }
}
  • 直接获取
<h3>{{$store.getters.getcount}}</h3>
  • 通过computed的计算属性直接赋值
<h3>{{count}}</h3>
computed: {
    count() {
      return this.$store.getters.getcount;
    }
  }
  • 通过mapGetters 的对象/数组来赋值
<h3>{{getcount}}</h3>
import { mapGetters } from 'vuex';
computed: mapGetters(['getcount'])

如果你想将一个 getter 属性另取一个名字,使用对象形式

<h3>{{count}}</h3>
import { mapGetters } from 'vuex';
 computed: mapGetters({
    // 把 `this.count` 映射为 `this.$store.getters.getcount`
    count: "getcount"
  })

需要注意的是,你写了这个配置后,在每次count 的值发生变化的时候,都会进行加100的操作。

  • mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
computed:{
...mapGetters(["getcount"])
}

5.Mutation修改状态

他是同步事务.
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

前面我们已经用到过了
2.开始demo

  • 提交载荷(Payload)
    你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):
    现在store.js文件里给add方法加上一个参数n。
//store.js
    const mutations={
        add(state,n){
            state.count+=n;
        },
        reduce(state){
            state.count-=1;
        }
    }
<button @click="$store.commit('add',10)">+10</button>
<button @click="$store.commit('reduce')">-1</button>
  • 模板获取Mutations方法
    实际开发中我们也不喜欢看到$store.commit( )这样的方法出现,我们希望跟调用模板里的方法一样调用。
    例如:@click=”reduce” 就和没引用vuex插件一样。
    在helloworld.vue上进行如下更改
    <button @click="add(10)">+10</button>
    <button @click="reduce">-1</button>
   import { mapMutations } from 'vuex';
    methods:mapMutations([
           'add','reduce'
   ]),

或者这么写,也可以

	<button @click="add10(10)">+10</button>
    <button @click="reduce1">-1</button>
   methods:{
   ...mapMutations({
   add10: 'add' ,// 将this.add10() 映射为 this.$store.commit('add')
   reduce1:'reduce'//其实就是方法又命名了一下
   })
   },

第二个参数可以是对象

 <button @click="$store.commit('reduce',{type:'reduce',nums:'2'})">-</button>
 reduce(state, payload) {
            state.count -= payload.nums
        },

6.actions异步修改状态

actions是异步的改变state状态,而Mutations是同步改变状态
在actions里写了两个方法addAction和reduceAction,在方法体里,我们都用commit调用了Mutations里边的方法。

context:上下文对象,这里你可以理解称store本身。
{commit}:直接把commit对象传递过来,可以让方法体逻辑和代码更清晰明了。

  • 方法调用
	<button @click="$store.dispatch('addAction')">+</button>
	<button @click="$store.dispatch('reduceAction')">-</button>
mutations: {
   add(state) {
        state.count += 1
    },
    reduce(state) {
        state.count -= 1
    },
},
actions: {
    addAction(context) {
        context.commit('add')
    },
    reduceAction({ commit }) {
        commit('reduce')
    },
},
  • 带参数调用
<button @click="$store.dispatch('addAction',5)">+</button>
mutations: {
        add(state, n) {
            state.count += n
        },
    },
    actions: {
        addAction(context, n) {
            context.commit('add', n)
        },
    },
// 以载荷形式分发
store.dispatch('add', {
amount: 10
})

// 以对象形式分发
store.dispatch({
type: 'add',
amount: 10
})
  • mapActions 辅助函数
<button @click="addAction">+</button>
<button @click="reduceAction">-</button>
import {  mapActions } from "vuex";
methods: mapActions(["addAction", "reduceAction"])
//
methods: {
    ...mapActions(["addAction", "reduceAction"])
  }

<button @click="add">+</button>
<button @click="reduce">-</button>
import {  mapActions } from "vuex";
methods: mapActions({ add: "addAction", reduce: "reduceAction" })
//
methods: {
    ...mapActions({ add: "addAction", reduce: "reduceAction" })
  }
  • 异步

action与mutations主要区别在于 异步操作的顺序执行问题,当A方法必须依赖于B方法执行的结果时
为什么要用Action管理异步操作

举个例子

<template>
  <div>
    <h3>{{count}}</h3>
    <div>
      <button @click="add">+</button>
      <button @click="reduce">-</button>
    </div>
  </div>
</template>
<script>
import { mapState, mapActions } from "vuex";
export default {
  computed: {
    ...mapState(["count"])
  },
  methods: {
    ...mapActions({ add: "addAction", reduce: "reduceAction" })
  }
};
</script>
export default new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        add(state) {
            state.count += 10
        },
        reduce(state) {
            state.count -= 1
        },
    },
    actions: {
        addAction({ commit }) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    commit('add')
                    resolve()
                }, 3000)
            })
        },
        reduceAction({ dispatch, commit }) {
            return dispatch('addAction').then(() => {
                commit('reduce')
            })
        }
    },
})

异步操作,此代码执行后,
reduceAction方法需先执行addAction
点击减号,等待3秒,count = 10,先执行addAction,在执行reduceAction.(1+10-1)
点击加号,紧接着点击减号,先变成11,紧接着变成20,先执行addAction,在执行addAction,reduceAction.(1+10 +10-1)

  • action 结合 async / await 例子
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

function getnumber(fun) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            fun('setCount', 100)
            resolve()
        }, 1000)
    })
}

export default new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        add(state) {
            state.count += 10
        },
        reduce(state) {
            state.count -= 1
        },
        setCount(state, data) {
            state.count = data
        },
    },
    actions: {
        async addAction({ commit }) {
            commit('add', await getnumber(commit)) //先异步请求数据,在执行add
        },
        async reduceAction({ dispatch, commit }) {
            await dispatch('addAction') // 等待 addAction 完成
            commit('reduce', await getnumber(commit)) //先异步请求数据,在执行reduce
        }
        // 同上
        // async addAction({ commit }) {
        //     commit('add', await new Promise((resolve, reject) => {
        //             setTimeout(() => {
        //                 commit('setCount', 10)
        //                 resolve()
        //             }, 1000)
        //         })) //先异步请求数据,在执行add
        // },
        // async reduceAction({ dispatch, commit }) {
        //     await dispatch('addAction') // 等待 addAction 完成
        //     commit('reduce', await new Promise((resolve, reject) => {
        //             setTimeout(() => {
        //                 commit('setCount', 10)
        //                 resolve()
        //             }, 1000)
        //         })) //先异步请求数据,在执行reduce 
        // }
    },
})

调用 addAction 方法 , 执行 setCount ->add
调用 reduceAction方法 , 执行 addAction(setCount ->add)->setCount ->reduce

7.module模块组

随着项目的复杂性增加,我们共享的状态越来越多,这时候我们就需要把我们状态的各种操作进行一个分组,分组后再进行按组编写。

代码如图所示
在这里插入图片描述
vue文件调用

<h1>moduleA:{{$store.state.moduleA.count}}</h1>
<h1>moduleB:{{$store.state.moduleB.count}}</h1>

重命名

export default new Vuex.Store({
    modules: {
        a: moduleA,
        b: moduleB
    }
})

调用时,将对应的名称更改即可

computed调用

computed: {
    a(){
      return this.$store.state.a.count
    }
  },
  
 //mapState
computed: mapState({
    a: state => state.a.count,
    //a: ({ a }) => a.count
    b(state) {
      return state.b.count;
    }
  }),

在模块中,state 是被限制到模块的命名空间下,需要命名空间才能访问。 但actions ,mutations 和 getters 却没有被限制,在默认情况下,它们是注册到全局命名空间下的,所谓的注册到全局命名空间下,其实就是我们访问它们的方式和原来没有module 的时候是一样的。

命名空间
demo(包含mapState, mapMutations, mapActions, mapGetters相关使用)

const moduleA = {
    namespaced: true,//命名空间
    state: {
        count: 1
    },
    mutations: {
        add(state, n) {
            state.count += n
        },
        reduce(state, n) {
            state.count -= n
        },
    },
    getters: {
        getcount: state => {
            return state.count += 100;
        }
    },
    actions: {
        addAction(context, n) {
            context.commit('add', n)
        },
        reduceAction({ commit }, n) {
            commit('reduce', n)
        },
    }
}

export default moduleA
<template>
  <div>
    mapState
    <h1>{{count}}</h1>
    <h1>{{$store.state.a.count}}</h1>

    mapGetters
    <h1>{{getcount}}</h1>
     <h1>{{$store.state.getcount}}</h1>
    mapMutations
    <button @click="add(10)">+</button>
    <button @click="reduce(5)">-</button>
    <br>
    <button @click="aaa">+</button>
    <button @click="bbb">-</button>
    <br>
    mapActions
    <button @click="addAction(10)">+</button>
    <button @click="reduceAction(5)">-</button>
    <br>
    <button @click="ccc">+</button>
    <button @click="ddd">-</button>
    <br>
    <div></div>
  </div>
</template>
<script>
import { mapState, mapMutations, mapActions, mapGetters } from "vuex";
export default {
  computed: {
    // ...mapState("a", {
    //   count: "count",
    //   count: state => state.count,
    //   count(state) {
    //     return state.count;
    //   }
    // }),
    ...mapState("a", ["count"]),

    //---------------------------------------------
    // ...mapGetters("a", {
    //   getcount : "getcount"
    // })
    ...mapGetters("a", ["getcount"])
  },
  methods: {
    // ...mapMutations("a", {
    //   add: "add",
    //   reduce: "reduce"
    // }),
    ...mapMutations("a", ["add", "reduce"]),

    aaa() {
      this.$store.commit("a/add", 10);
      // this.add(10);
    },
    bbb() {
      // this.$store.commit('a/reduce',5);
      this.reduce(5);
    },

    //---------------------------------------
    // ...mapActions("a", {
    //   addAction: "addAction",
    //   reduceAction: "reduceAction"
    // }),
    ...mapActions("a", ["addAction", "reduceAction"]),
    ccc() {
      this.$store.dispatch("a/addAction", 10);
      // this.add(10);
    },
    ddd() {
      // this.$store.dispatch('a/reduceAction',5);
      this.reduce(5);
    }
  }
};
</script>

根store
那么怎样才能获取到根store 中的state 和 getters 呢? Vuex 提供了 rootState, rootGetters 作为module 中 getters 中默认参数, actions中context 对象,也会多了两个属性,context.getters, context. rootState, 这些全局的默认参数,都排在局部参数的后面。

Logo

前往低代码交流专区

更多推荐