浅谈vuex源码分析

vuex使用方式

store/index.js

import Vue from 'vue'
import Vuex from '@/vuex'
// import Vuex from 'vuex'
// import logger from 'vuex/dist/logger.js'
Vue.use(Vuex)
// // new Vue

let store = new Vuex.Store({
    
    state: {
    // state = > data
        name: 'zhufeng',
        age: 12
    },
    mutations: {
    // method  commit 同步更改状态
        changeAge(state, payload) {
   
            state.age += payload
        }
    },
    actions: {
    // 异步操作 调用api接口 dispatch, 多次commit mutation  
        changeAge({
    commit }, payload) {
   
            setTimeout(() => {
   
                commit('changeAge', payload);
            }, 1000);
        }
    },
    getters: {
    // 计算属性
        myAge(state) {
   
            return state.age + 10
        }
    },
    strict: true, // 如果不是在mutation中操作的状态会发生警告
    modules: {
    // 进行模块分割
        // namespaced 能解决子模块和父模块的命名冲突文件 ,相当于增加了一个命名空间
        // 如果没有namespaced 默认getters都会被定义到父模块上,
        // mutations 会被合并在一起, 最终一起调用,有了命名空间就没有这个问题了
        // 子模块的名字不能和父模块中的状态重名
        a: {
   
            namespaced: true,
            state: {
   
                name: 't1',
                age: 10
            },
            // 所有的getters 都会被合并到跟上
            getters: {
    // 首页一个模块 home 订单页一个模块 order  用户一个模块 user
                myAge(state) {
   
                    return state.age + 20;
                }
            },
            mutations: {
   
                changeAge(state, payload) {
   
                    state.age += payload
                }
            },
            modules: {
   
                c: {
   
                    namespaced: true,
                    state: {
   
                        age: 100
                    },
                    mutations: {
   
                        changeAge(state, payload) {
   
                            state.age += payload
                        }
                    },
                    modules: {
   
                        d: {
   
                            namespaced: true,
                            state: {
   
                                age: 100
                            },
                        }
                    }
                }
            }
        },

    }
})

export default store;

1、 初始化

一开始Vue.use(Vuex): Vue.use就是使执行vuex的install方法
Vuex里面有个install方法, 用于执行install()

install.js

export let Vue;
function install(_Vue) {
   
    Vue = _Vue;
    Vue.mixin({
   
        beforeCreate(){
    //this代表的是每个组件实例
            // 获取根组件上的store 将他共享给每个组件
            // 每个组件中都应该有$store
            let options= this.$options;
            if(options.store){
   
                // 根
                // console.log('根',options.name)
                this.$store = options.store
            }else{
   
                // 先保证他是一个子组件,并且父亲上有$store
                if(this.$parent && this.$parent.$store){
   
                    this.$store = this.$parent.$store
                }
            }
        }
    })
} 
// 父  this.$store -》 子 this.$store -》孙子 this.$store
export default install

install方法: 传入了_Vue, 是为了拿到全局vue对象,统一vue版本, 同时执行minxin方法,各个组件等到执行beforeCreate生命周期时:给每个vue实例获取根对象的store,每个vue实例就有$store对象了。

2、创建store对象 — 创建模块收集器对象

let store = new Vuex.Store({
    
  ...
})

这一步说明了Vuex.Store是一个构造函数

vuex/store.js

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中更改的

        this.strict = options.strict;


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

        installModule(this, state, [], this._modules.root);

        resetVM(this, state);
        if (options.plugins) {
    // 说明用户使用了插件
            options.plugins.forEach(plugin => plugin(this))
        }
    }
    _withCommittting(fn) {
   
        this._committing = true; // 如果true
        fn(); // 函数是同步的 获取_commiting 就是true,如果是异步的那么就会变成false 就会打印日志
        this._committing = false;
    }
    subscribe(fn) {
   
        this._subscribes.push(fn);
    }
    replaceState(newState) {
    // 需要替换的状态

        this._withCommittting(() => {
   
            this._vm._data.$$state = newState; // 替换最新的状态, 赋予对象类型会被重新劫持
        })

        // 虽然替换了状态,但是mutation getter中的state在初始化的时候 已经被绑定死了老的状态
    }

    get state() {
   
        return this._vm._data.$$state
    }
    commit = (mutationName, payload) => {
    // 发布
        this.mutations[mutationName] && this.mutations[mutationName].forEach(fn => fn(payload))
    }
    dispatch = (actionName, payload) => {
   
        this.actions[actionName] && this.actions[actionName].forEach(fn => fn(payload))
    }

    registerModule(path, module) {
    // 最终都转换成数组  register(['a','c'])
        if (typeof path == 'string') path = [path];

        // module 是用户直接写的
        this._modules.register(path, module); // 模块的注册, 将用户给的数据放到树中
        // 注册完毕后 ,在进行安装

        // 将用户的module 重新安装
        installModule(this, this.state, path, module.newModule);

        // vuex内部重新注册的话 会重新生成实例, 虽然重新安装了 ,只解决了状态的问题,但是computed就丢失了
        resetVM(this, this.state); // 销毁重来
    }
}

一开始 this._modules = new ModuleCollection(options);

ModuleCollection是一个模块收集器:传入用户定义的所有选项options。

vuex/module/module-collection.js

import {
    forEach } from '../util'
import Module from './module';
class ModuleCollection {
   
    constructor(options) {
   
        // 对数据进行格式化操作
        this.root = null;
        this.register([],options); // 为了记录父子关系 
    }
    getNamespace(path){
    // [a,b,c]
        // 返回一个字符串 a/b/c   ''
        let root = this.root
        let ns =  path.
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值