严格模式

import { Vue } from './install'
import ModuleCollection from './module/module-collection';
import { forEach } from './util';

function getNewState(store, path) {
    return path.reduce((memo, current) => {
        return memo[current];
    }, store.state)
}

function installModule(store, rootState, path, module) { //  a/b/c/d
    // 获取 moduleCollection 类的实例
    let ns = store._modules.getNamespace(path);

    // module.state => 放到 rootState 对应的儿子里(按层级放)
    if (path.length > 0) { // 儿子模块 
        // 需要找到对应父模块,将状态声明上去
        // {name: 'zhangsan', age: '12', a: aState}
        let parent = path.slice(0, -1).reduce((memo, current) => {
            return memo[current];
        }, rootState);
        // 对象新增属性不能导致重新更新视图
        store._withCommittting(() => {
            // 将新增属性变成响应式的
            Vue.set(parent, path[path.length - 1], module.state);
        })
    }

    // 遍历 getters 放入 store.wrapperGetters 中
    module.forEachGetter((fn, key) => {
        store.wrapperGetters[ns + key] = function () {
            // 防止 this 丢失
            return fn.call(store, getNewState(store, path));
        }
    });
    // 遍历 mutation 放入 store.mutation
    module.forEachMutation((fn, key) => {
        // {myAge:[fn,fn]},没有命名空间的时候,要合并相同名字的 mutation
        store.mutations[ns + key] = store.mutations[ns + key] || [];
        store.mutations[ns + key].push((payload) => {
            store._withCommittting(() => {
                // 防止 this 丢失
                fn.call(store, getNewState(store, path), payload); // 先调用 mutation 再执行 subscirbe
            })

            // 插件的更新依赖于 mutations 的执行
            store._subscribes.forEach(fn => fn({ type: ns + key, payload }, store.state));
        })
    });
    // 遍历 action 放入 store.action
    module.forEachAction((fn, key) => {
        store.actions[ns + key] = store.actions[ns + key] || [];
        store.actions[ns + key].push((payload) => {
            // 防止 this 丢失
            return fn.call(store, store, payload)
        })
    });

    // 递归安装
    module.forEachChildren((child, key) => {
        installModule(store, rootState, path.concat(key), child);
    });
}

function resetVM(store, state) {
    let oldVm = store._vm;

    store.getters = {}; // 初始化 store.getters
    const computed = {}; // 取 getters 属性时,把他代理到 vue 实例的计算属性 computed 上
    forEach(store.wrapperGetters, (getter, key) => {
        computed[key] = getter;

        // 给 store.getters 赋值
        Object.defineProperty(store.getters, key, {
            // 在 vue 组件中使用 vuex 的 getters 时,代理到 vue 实例 store._vm 上
            get: () => store._vm[key]
        })
    });

    // 需要将 state 变成响应式的,直接将 state 放到 vue 实例的 data 里面就可以了,这样 state 就是响应式的,会自动更新视图
    store._vm = new Vue({
        data: {
            // 以 $ 开头的数据不会被挂载到实例上,但是会挂载到当前的 _data 上,减少一次代理
            // $$ 开头,表示是 vuex 自己自定义的变量
            $$state: state
        },
        computed,
    });

    // 说明是严格模式要监控状态(利用 watch)
    // 异步修改状态必须通过 commit mutation
    if (store.strict) {
        store._vm.$watch(() => store._vm._data.$$state,
            () => {
                // console.assert() 方法在第一个参数为 false 的情况下会在控制台输出信息
                console.assert(store._committing, 'no mutate in mutation handler outside')
            },
            {
                deep: true, // 内部会遍历所有的属性
                sync: true  // 状态变化,会立即执行(同步)
            }
        ); 
    }

    if (oldVm) { // 重新创建实例后,需要将老的实例卸载掉
        Vue.nextTick(() => oldVm.$destroy())
    }
}

class Store {
    constructor(options) {
        // 对用户的模块进行整合,整合成一棵树
        // 当前格式化完毕的数据,放到了 this._modules 里
        this._modules = new ModuleCollection(options); // 对用户的参数进行格式化操作
        this.wrapperGetters = {};

        // 需要将模块中的所有的 getters、mutations、actions 进行收集
        this.mutations = {};
        this.actions = {};
        this._subscribes = []; // 插件集合(发布订阅模式)
        this._committing = false; // 标记:是否通过 mutation 修改的属性,默认不是在 mutation 中更改的

        this.strict = options.strict;

        // 没有 namespace 的时候 getters 都放在根上,actions 和 mutations 会被合并数组
        let state = options.state;

        // 将包装后的模块进行安装
        installModule(this, state, [], this._modules.root);

        // getters 计算属性的实现
        resetVM(this, state);

        // 说明用户使用了插件
        if (options.plugins) {
            options.plugins.forEach(plugin => plugin(this))
        }
    }
    // 判断修改 state 是同步还是异步修改
    _withCommittting(fn) {
        this._committing = true; // 如果 true
        fn(); // 函数是同步的 获取_commiting 就是 true,如果是异步的那么就会变成 false 就会打印日志
        this._committing = false;
    }
}

// state getters action mutation  (modules 分层)
export default Store;
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 严格模式