mini-vuex:实现简易响应式全局状态管理

521 阅读1分钟

在vue项目中有时某些组件之间需要共同维护一个全局状态,使用vuex又没有必要的时候,可使用此响应式全局状态管理。

功能

  • 全局状态管理
  • 类型检查
  • 默认值设置
  • 修改状态监控
  • 响应式

使用

// 定义状态
const storeConfig = {
    // 当前套餐id
    count: {
        type: Number,
        default: 0
    },
    str: {
        type: [String, undefined],
        default: ''
    }
};
const store = new StoreFactory(storeConfig);
Vue.prototype.$state = Vue.observable(store.state); // 响应式挂载state
Vue.prototype.$store = store; // 响应式挂载state
// vue组件
export default {
    mounted() {
        console.log(this.$state.count); // 0
        this.$store.setState('count', 1); // setState -> 1
        this.$store.setState('count', 'string'); // type check error
    },
    watch: {
        $state: {
            deep: true,
            handler() {
                console.log('$state change:', this.$state);
            }
        },
        '$state.count': {
            deep: true,
            handler() {
                console.log('$state.count change:', this.$state.count);
            }
        }
    }
}

源码

/*
* 作者: Alan
* 日期:2020.11.19
* 功能:store模式:简单易用的全局状态管理工具
*/
/**
* 构造函数实现store模式,简单易用的全局状态管理工具
* @class {Function} Store
* @param {Object} initialState  初始化状态对象
*/
function StoreFactory(option) {
    const Vue = option.Vue;
    const initialState = option.states;
    // 要返回的状态映射map
    this.state = {};

    for (let prop in initialState) {
        if (initialState.hasOwnProperty(prop)) {
            const state = initialState[prop];
            const type = state.type;
            const typeStr = typeOf(type);
            if (!['function', 'array', 'undefined', 'null'].includes(typeStr)) {
                throw new Error('Type of state must be one of: Array, Constructor, undefined, null!');
            }
            this.state[prop] = initialState[prop].default;
        }
    }
    this.state = Vue.observable(this.state);
    /**
    * 设置单个状态,会判断属性是否在satate中初始化,并且检查类型是否一致
    * @param {String} prop  状态名
    * @param {String} val  状态的值
    */
    this.setSingleState = function(prop, val) {
        const typeCheckSuccess = typeCheck(prop, val);
        if (typeCheckSuccess === true) {
            console.log('setState:', prop, '->', val);
            this.state[prop] = val;
        } else {
            throw new Error(typeCheckSuccess);
        }
    };
    /**
    * 设置状态,参数可以用对象一次修改多个状态,也可以由键值对修改单个状态
    * @param {String|Object} state  状态名|状态名和状态值键值对组成的对象
    * @param {Any} val  状态的值|第一个参数是对象时,不需要第二个参数
    */
    this.setState = function(state, val) {
        if (typeOf(state) === 'object') {
            for (let prop in state) {
                if (state.hasOwnProperty(prop)) {
                    this.setSingleState(prop, state[prop]);
                }
            }
        } else {
            this.setSingleState(state, val);
        }
    };
    /**
    * 获取状态,只可以通过此方法获取状态的值
    * @param {String} prop  状态名
    * @return {String} val  返回状态的值
    */
    this.getState = function(prop) {
        if (prop === undefined) {
            return this.state;
        }
        if (!initialState.hasOwnProperty(prop)) {
            console.error(`The prop ${prop} of state is undefined!'`);
        }
        // console.log('getState:', prop);
        return this.state[prop];
    };
    /**
    * 状态类型校验
    * @param {String} prop  状态名
    * @param {Any} value  状态值
    * @return {Boolen|String} 校验是否成功
    */
    function typeCheck (prop, value) {
        let errorMsg = '';
        if (initialState.hasOwnProperty(prop)) {
            const state = initialState[prop];
            const type = state.type;
            const typeStr = typeOf(type);
            if (typeStr === 'function') {
                if (!isExpectType(value, type)) {
                    errorMsg = `The type of the state ${prop} must be ${type.name}, but get ${typeOf(value)}!'`;
                }
            } else if (typeStr === 'array') {
                let typeCheckSuccess = false;
                for (let i = 0; i < type.length; i ++) {
                    const constructorFun = type[i];
                    if (isExpectType(value, constructorFun)) {
                        typeCheckSuccess = true;
                        break;
                    }
                }
                if (!typeCheckSuccess) {
                    const typeStr = type.map(fun => fun.name).join('|');
                    errorMsg = `The type of the state ${prop} must be one of ${typeStr}, but get ${typeOf(value)}!'`;
                }
            } else if (type === undefined || type === null) {
                if (value !== type) {
                    errorMsg = `The type of the state ${prop} must be ${type}, but get ${typeOf(value)}!'`;
                }
            } else {
                errorMsg = 'State type error!';
            }
        } else {
            errorMsg = `The prop ${prop} of state is not defined!'`;
        }
        return errorMsg ? errorMsg : true;
    }
    /**
    * 是否是预期设置的类型
    * @param {Any} value 状态值
    * @param {Function} type 类型:构造函数或undefined、null
    * @return {Boolean} 是否是预期设置的类型
    */
    function isExpectType (value, type) {
        if (type === undefined || type === null) {
            return value === value;
        }
        return typeOf(value) === type.name.toLowerCase();
    }
    /**
    * 判断变量类型
    * @param {Any} param 参数
    * @return {String} 变量类型
    */
    function typeOf(param) {
        return Object.prototype.toString.call(param).slice(8, -1).toLowerCase();
    }
}