XFE 技术 生活 笔记 文集

vuex源码分析

🔖 javascript 👀 317 🕒 2019-07-26 👨‍🎓 戡玉

代码设计

代码量

3.11版本的代码编译后为1017行

目录结构

代码结构

index入口

也就是import Vuex from 'vuex'指向的地方,然后可以进行new Vuex.Store()

import { Store, install } from "./store.js";
import {
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
} from "./helpers.js";
export default {
  Store,
  install,
  version: "__VERSION__",
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
};
// index.esm.js只多了这个
export {
  Store,
  install,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}

核心实现

store.js内容的大体结构

// import ...
// 其他模块都是辅助模块
let Vue;
export class Store {
    // prototype fns...
}
// global fns...
export function install(_Vue) {
  Vue = _Vue;
  applyMixin(Vue);
}

代码实现

库的注册

主要是在store引入的applyMixin函数中实现的

export default function (Vue) {
  const version = Number(Vue.version.split('.')[0])
  // 判断版本
  if (version >= 2) {
    // 通过混入钩子函数进行注册
    Vue.mixin({ beforeCreate: vuexInit })
  } else {
    // 覆盖init并注入vuex init,以实现1.x的向后兼容
    const _init = Vue.prototype._init;
    Vue.prototype._init = function (options = {}) {
      options.init = options.init ? [vuexInit].concat(options.init) : vuexInit;
      _init.call(this, options)
    }
  }
  // 将传入Vue构造器的options属性store挂载到vue的实例属性上
  function vuexInit () {
    const options = this.$options
    if (options.store) {
      this.$store = typeof options.store === 'function'
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
  }
}

Store实例化

基本用法

// 基本用法
new Vuex.Store({
  actions,
  getters,
  state,
  mutations,
  modules
})

初始化过程

export class Store {
  constructor(options = {}) {
    // 如果非模块环境,就用window注册
    if (!Vue && typeof window !== "undefined" && window.Vue) {
      install(window.Vue);
    }
    const { plugins = [], strict = false } = options;
    // 初始化一系列属性
    this._committing = false;
    this._actions = Object.create(null);
    this._actionSubscribers = [];
    this._mutations = Object.create(null);
    this._wrappedGetters = Object.create(null);
    this._modules = new ModuleCollection(options);
    this._modulesNamespaceMap = Object.create(null);
    this._subscribers = [];
    this._watcherVM = new Vue();
    // 劫持上下文(保证函数被调用时的上下文始终是实例本身)
    const store = this;
    const { dispatch, commit } = this;
    this.dispatch = function boundDispatch(type, payload) {
      return dispatch.call(store, type, payload);
    };
    this.commit = function boundCommit(type, payload, options) {
      return commit.call(store, type, payload, options);
    };
    // 严格模式
    this.strict = strict;
    const state = this._modules.root.state;
    // 注册模块
    installModule(this, state, [], this._modules.root);
    // 实现vuex状态的响应式
    resetStoreVM(this, state);
    // 插件执行
    plugins.forEach(plugin => plugin(this));
    // 游览器devtools插件与vuex的捆绑
    const useDevtools =
      options.devtools !== undefined ? options.devtools : Vue.config.devtools;
    if (useDevtools) {
      devtoolPlugin(this);
    }
  }
}

模块实现

export class Store {
  constructor(options = {}) {
    ...
    // 模块生成
    this._modules = new ModuleCollection(options);
    ...
    // 模块注册
    installModule(this, state, [], this._modules.root);
  }
}

模块生成

模块注册

响应式

state/getters/mutations/actions访问

commit/dispatch操作

辅助函数

插件

未完待续...