# Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

换成我们大白话来说:Vuex就是一个状态管理模式,可以简单的理解为一个全局对象,然后我们可以修改这个全局对象里面的属性或者添加方法,但是我们不能像传统JS的那种直接赋值形式来修改,我们必须得按照Vuex给我们提供的规则来修改;

Vuex一共给我们提供了四大对象,分别是state、mutations、getters、actions;

  • state:Vuex中的数据源,我们所需要的公共数据都是存储在这,可以简单理解为一个透明的仓库,可以通过this.$store.state.变量名来访问这个仓库里面的数据源;
  • mutations:mutations相当于是这把仓库的钥匙,只有通过提交mutations才能进行修改数据源操作,也就是说你想更改这个仓库里面的数据就只有通过mutations来进行修改(this.$store.commit("方法名"));
  • getters:getters类似于vue中的computed属性,getters的返回值会根据state中所依赖的值的状态修改来进行改变,如果getters中依赖的state中的值没有变化,直接读的是缓存,如果有变化这里也会发生相应的变化,可以用于监听state的值的变化;这里的getters可以理解为state这个仓库的保安,如果state的数据发生变化,这个保安就会采取相应措施进行相应变化,如果没有发生变化,则啥事没有则继续混吃等死(哈哈哈,不知道比喻恰不恰当,但是是这个意思,大家理解就好,别杠精)
  • actions:actions和mutations很类似,只是mutations官方规定只能进行同步操作,而actions里是可以进行异步操作的;也就是说我们需要进行异步操作需要在actions中来进行,然后就是actions提交的是mutations,而不是直接修改状态的,也就是说进入这个仓库修改数据,要先去拿到钥匙才能修改,所以actions是提交给mutations再去执行mutations的方法的;

# 一、state的用法

首先我们新建一个项目,搭建vue的环境我们这里就不多赘述了,毕竟本文是讲述vuex的;先在项目中安装vuex:

npm install vuex --save

安装完vuex之后我们在src的目录下新建一个vuex文件夹,同时在vuex文件夹中新建一个store.js文件:

import Vue from 'vue';
import Vuex from 'vuex';


Vue.use(Vuex);
const state={
  number:1
}

export default new Vuex.Store({
  state,
})

然后我们在main.js中引用store.js,并将实例化对象的时候加入store对象

import Vue from 'vue'
import App from './App'
import router from './router'
//引用store.js
import store from './vuex/store'

Vue.config.productionTip = false


/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
//实例化的时候加入store对象
  store,
  components: { App },
  template: '<App/>'
})

然后修改一下我们的App.vue文件

<template>
  <div id="app">
    <img src="./assets/logo.png">
//视图层加数据方便观察
    <p>{{this.$store.state.number}}</p>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

通过上述代码我们可以看到,我们在App.vue中加入了一个p标签,vuex规定:如果我们需要读取vuex中的数据,也就是state的数据源仓库,我们必须通过this.$store.state.变量名访问

# state更新实时渲染是基于computed这个计算属性的,直接赋给data只能赋值初始值,不会随着state改变实时渲染

<!--state改变不会实时渲染-->
export default {
    data() {
    	return {
    		name:this.$store.state.name,
    	};
    },
}
<!--监听state改变重新渲染视图-->
<template>
    <div>
        {{name}}
    </div>
<template>
export default {
    computed: {
    	name() {
    		return this.$store.state.name;
    	}
    },
}

注意: data中的变量如果和computed中的变量重名,data优先,注意命名

# 获取多个state值,写多个函数return,很繁琐,所以有mapState辅助函数

<!--取多个很冗余,繁琐-->
export default {
    computed: {
    	token(){
    		return this.$store.state.token;
    	}name(){
    		return this.$store.state.name;
    	}
    },
}
<!--mapState 直接取出-->
import { mapState } from 'vuex'
export default {
    computed: mapState([
      'token''name'
    ])
}

# 我们有局部计算,怎么和mapState一起用?

import { mapState } from 'vuex'
export default {
    computed:{
        getTime(){
            return 123;
        },
        ...mapState([
          'token''name'
        ])
    }
}

# 我们为它起个别名

<template>
    <div>
        xiaokeai,dahuilang是我们取的别名
        token,name是state的值
        {{xiaokeai}}
    </div>
<template>
<script>
    import { mapState } from 'vuex'
    export default {
        computed:{
            ...mapState({
                xiaokeai:"token",
                dahuilang:"name",
            })
        }
    }
</script>

# 我们要state和data发生点什么

<template>
    <div>
        假如token的值123;
        balabala的值就是 123皮卡皮
        {{balabala}}
    </div>
<template>
<script>
    import { mapState } from 'vuex'
    export default {
        data(){
            return {
                pikaqiu:"皮卡皮卡"
            }
        }
        computed:{
            ...mapState({
                xiaokeai:"token",
                dahuilang:"name",
                // 为了能够使用 `this` 获取局部状态,使用一个自定义名字的函数
                balabala(state){
                   return state.token + this.pikaqiu;
                }
            })
        }
    }
</script>

# 二、mutations的用法

如果我们需要修改vuex中的数据源,我们可以通过提交mutations来进行修改;

首先我们需要在我们的视图层App.vue加个按钮来控制:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <p>{{$store.state.number}}</p>
    //加个按钮触发事件修改数据源
    <button @click="add">按钮</button>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods:{
    add(){
    //要修改数据源就要根据vuex规定的方法来
      this.$store.commit('addFunction');
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

然后修改我们的store.js

import Vue from 'vue';
import Vuex from 'vuex';


Vue.use(Vuex);
const state={
  number:1
}

//添加mutations对象,state参数能获取到上面的state
const mutations={
  addFunction(state){
    return state.number+=1;
  }
}

//这里一定要记得要加入到实例中,不然会报错
export default new Vuex.Store({
  state,
  mutations
})

我们可以很直观的看到,通过this.$store.commit('方法名')来提交mutations修改数据源,当然我们的mutations也是可以接收参数的,第一个参数为mutations的方法名,第二个参数为mutations需要接收的参数,这样我们的mutations就变得更加的灵活;

# 三、getters的用法

getters类似于vue的computer用法,可以监听state数据源这个仓库的数据变化,如果getters依赖state的数据发生了变化,getters中依赖的数据发生了变化state也会发生变化

首先我们可以在store.js中添加以下代码:

import Vue from 'vue';
import Vuex from 'vuex';


Vue.use(Vuex);
const state={
  number:1
}

const getters={
    //通过方法触发  state是上面的state对象,能读取state的值
  addFunction(state){
    return state.number++;
  }
}
export default new Vuex.Store({
  state,
//这里一定要记得在实例化的时候加入对象
  getters
})

App.vue中的视图我们可以这样更改

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <p>页面的值:{{$store.state.number}}</p>
    //加入一个标签跟页面的值做对比
    <p>我的getters的值:{{$store.getters.addFunction}}</p>
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

通过上述代码以及视图层我们可以清晰的看到,当我们操作了getters的时候,触发了getters的addFunction方法,addFunction方法会改变state.number的值,这个时候number的值已经为2了,所以页面上会显示值为2,因为++在后,所以getters此时的值为1,也就是说当getters依赖的state.number的值在getters中发生变化的时候,state.number就会发生变化,如果state.number没有发生变化,此时getters会优先读缓存;

# 取个对象值怎么破

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
	state: {
		obj: {
			yeye: {
				baba: {
					daSon: "老大",
					xiaoSon: "老二"
				}
			}
		}
	},
	getters: {
        <!--将想要提取或者处理的值这里处理好-->
		getson: state => {
			return state.obj.yeye.baba;
		}
	}
})

export default store


<!--用的时候,和state一样,也可以别名等等操作-->
<template>
	<div>
        {{getson}}
	</div>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
  computed: {
    ...mapGetters([
        getson
    ])
  }
}
</script>

# 四、actions的用法

actions对象里面主要是进行异步操作,类似于mutations,不同的是actions通过提交mutations来进行更改数据,而不是直接变更数据状态;

首先我们可以更改store.js中的代码:

import Vue from 'vue';
import Vuex from 'vuex';


Vue.use(Vuex);
const state={
  number:1
}
const mutations={
  addFunction(state){
    return state.number++;
  }
}
const getters={
  addFunction(state){
    return state.number++;
  }
}
//context是具有store实例一样的属性和方法的对象
const actions={
  addFunction(context){
    context.commit("addFunction");
  }
}
export default new Vuex.Store({
  state,
  mutations,
  getters,
//这里记得要在实例化的时候要加上
  actions
})

App.vue中代码修改为:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <p>页面的值:{{$store.state.number}}</p>
     <button @click="add">按钮</button>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods:{
    add(){
//actions中通过this.$store.dispatch来提交mutations进行修改
      this.$store.dispatch("addFunction")
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

# 五、插件

# 1.vuex-persistedstate

vuex页面刷新会丢失数据,用vuex-persistedstate插件可解决

import createPersistedState from "vuex-persistedstate";

const store = new Vuex.Store({
	state: {},
	mutations: {},
	actions: {},
	getters: {},
	modules:{},
    plugins: [
        createPersistedState({
            storage: window.sessionStorage
        })
    ]
})

export default store
更新时间: 4/20/2020, 2:56:50 PM