vuex 状态管理

102 阅读3分钟

vuex 状态管理

状态管理(集中式存储管理应用的所有组件的状态), 它最大的特点是响应式。

Vuex有哪些属性

state: {},    ==> 就是来放入数据的[类似于组件中的data]
getters:{},   ==> 获取data中的数据,类似计算器属性
mutations: {},   ==> 用来修改 data中的数据
actions: {},  ==> 用来发异步请求, 吩咐mutations去更新数据
modules: {},   ==>模块化数据仓库

使用步骤

安装:

yarn add vuex // 安装最新的
yarn add vuex@3   // 指定版本安装

注意根据vue版本来选择vuex的版本, 如果vue是版本2 , vuex 选择版本3

安装vuex

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

// 实例化一个vuex实例化对象
var store = new Vuex.Store({
    state:{
        count:1,
        userInfo:{
            role:['admin'],
            menus:['/home'],
            username:'alice'
        }
    }
})

export default store;

在vue实例上挂载

import store from './store/index'
var vm = new Vue({
  // 会自动将store对象注入到所有子组件中
  // 组件中可以通过this.$store获取到
  store:store,  // 挂载store
  render: h => h(App),
  router:router
}).$mount('#app')

vuex 有如下五个核心模块:

state:

  • 用于存放组件间互相通信的属性值。
  • 原则上 state 中的属性只能在各个组件之间使用,而不能修改,如果要修改需要在 mutations 中修改
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

// 实例化一个vuex实例化对象
var store = new Vuex.Store({
    state:{
        count:1,
        userInfo:{
            role:['admin'],
            menus:['/home'],
            username:'alice'
        }
    }
})

export default store;

在组件中获取数据

{{ $store.state.userInfo }}

或者通过mapState 获取

import {mapState} from 'vuex'
....
computed:{
        ...mapState(['count','todolist'])
    }
....

getters

  • 这里也是一些函数,类似于组件中的计算属性
  • 可以处理一些通用且复杂的逻辑, 实际使用比较少

// 实例化一个vuex实例化对象
var store = new Vuex.Store({
    ....
    getters:{
        todoFinished(state){
           var finishedTodo =  state.todolist.filter((item)=>{
                return item.finished
            })
            return finishedTodo;
        }
    }
})

mutations

  • 这里存放的都是一些函数,用于修改 state 中的属性值

  • 这里的函数中只接收两个参数:state 和 options

  • 这里面的函数必须都是同步的

  • 如果某组件中需要修改 state 中的属性值,则需在该组件中用this.$store.commit (’ 方法名 ', 参数) 的方式来调用,即需要用 commit 方法来 调用 mutations 中的函数

  • 通过 commit 触发

    //定义
    export default new Vuex.Store({
        mutations:{
            changeUserInfo(state,name){
                state.userinfo.name = name;
            }
        }
    })
    //使用
    this.$store.commit("changeUserInfo", "Yannis")
    this.$store.commit({
    	type:'changeUserInfo',
    	data:'Yannis'
    })
    

actions

  • 这里存放的也都是一些函数,这里的函数可以是异步的
  • 这里的函数也是接收两个参数:store 和 options
  • 如果这里的函数想要修改 state 中的值,还是得通过调用 mutations 中的方法来实现
  • 如果想要在组件中调用这里的函数,则需要用 dispatch 方法调用:this.$store.dispatch (’ 方法名 ', options)
  • 通过 dispatch 触发

modules

  • 用于划分模块
  • 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象显得会相当臃肿
  • 为了解决上面的问题,Vuex 允许将 store 分割成模块。每个模块拥有自己的 state、mutation、action、getter 甚至是嵌套子模块
  • 如果模块中的 mutations 或 actions 重复,则两个重复的方法都会执行
  • 如果想区分模块中重复的 mutations 或 actions,则可以在模块中加一个属性:namespaced:true 即可,调用时需要指定模块名,例如:this.$store.commit (’ 模块名 / 方法名 ')

Vuex持久化存储

1 使用插件vuex-persistedstate

1.1 安装

yarn add vuex-persistedstate // 或 npm install --save vuex-persistedstate

1.2 配置

import Vuex from "vuex";
// 引入插件
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

const store = new Vuex.Store({
    state,
    mutations,
    actions,
    /* vuex数据持久化配置 */
    plugins: [
        createPersistedState({
            // 存储方式:localStorage、sessionStorage、cookies
            storage: window.sessionStorage,
            // 存储的 key 的key值
            key: "store",
            render(state) {
            // 要存储的数据:本项目采用es6扩展运算符的方式存储了state中所有的数据
                return { ...state };
            }
        })
    ]
});

export default store;

2. 方法是 vuex-along

(1)安装 vuex-along

npm install vuex-along --save

(2)在store文件夹里的index.js中引入vuex-along并配置相关代码

import Vue from 'vue'
import Vuex from 'vuex'
import indexOne from "./modules/indexOne"
import VueXAlong from 'vuex-along'

Vue.use(Vuex)
const store=new Vuex.Store({
    strict: false,
    modules:{
        indexOne
    },
    plugins: [VueXAlong({
        name: 'along',     //存放在localStroage或者sessionStroage 中的名字
        local: false,      //是否存放在local中  false 不存放 如果存放按照下面session的配置配
        session: { list: [], isFilter: true }   
        //如果值不为false 那么可以传递对象 其中 当isFilter设置为true时, list 数组中的值就会被过滤调,这些值不会存放在seesion或者local中
      })]

})

export default store;

3. vuex-persist

(1)安装 vuex-persist

npm install --save vuex-persist
or
yarn add vuex-persist

(2)在store文件夹里的index.js中引入vuex-persist并配置相关代码

import Vue from 'vue'
import Vuex from 'vuex'
import indexOne from "./modules/indexOne"
import VuexPersistence from 'vuex-persist'
Vue.use(Vuex)

const vuexLocal = new VuexPersistence({
    storage: window.localStorage
})

const store = new Vuex.Store({
    strict: false,
    modules:{
        indexOne,
    },
    plugins: [vuexLocal.plugin]
     
  }) 

export default store;

结语:

其实解决此问题的方法有很多,基本上都是要借助于localStorage或者sessionStroage来存放**。

基于 vuex 的原理模拟部分 Vuex 源码

let Vue = null;
function install(_Vue){
	Vue = _Vue;
	Vue.mixin({
		beforeCreate(){
			if(this.$options.store){
				//说明是根实例
				this$store = this.$options.$store
			}else if(this.$parent){
				//有$parent属性,说明这个组件是根组件的后代组件
				this.$store = this.$parent.$store
			}
		}
	});
}

class Store{
	constructor(options){
		//this.state = options.state;//没有响应式
		let vm = new Vue({
			data:{
				state: options.state
			}
		});
		this.state = vm.state;
		this.mutations = {};
		let mutations = options.mutations || {};
		Object.keys(mutations).forEach(key => {
			this.mutations[key] = (option) => {
				mutations[key].call(this,this.state, option);
			}
		});
	
		this.actions = {};
		let actions = options.actions || {};
		Object.keys(actions).forEach(key => {
			this.actions[key] = (option) => {
				actions[key].call(this, this.store, option);
			}
		});

		this.getters = {};
		let getters = options.getters || {};
		Object.keys(getters ).forEach(key => {
			Object.defineProperty(this.getters, key, {
				get:() => {
					return getters[key].call(this, this.state);
				}
			})
		});
	
		this.commit = (type, option) => {
			this.mutations[type](option);	
		}
		
		this.dispatch = (type, option) => {
			this.actions[type](option);
		}
	}
	/*
	* commit 和 dispatch应该是stote私有的
	commit(type, option){
		this.mutations[type](option );
	}
	
	dispatch(type, option){
		this.actions[type](option);
	}
	*/
}

//辅助函数
export function mapState(arr){
	let obj = {};
	arr.forEach(key => {
		obj[key] =  function(){
			return this.$store.state[key]
		}
	});
	return obj;
}

export function mapMutation(arr){
	let obj = {};
	arr.forEach(key => {
		obj[key] =  function(option){
			return this.$store.commit(key, option)
		}
	});
	return obj;
}

export default {
	install,
	Store
}