实现简易版Vuex

从实现一个简单的 Vuex 类来了解 Vuex 的工作原理。

实现思路

Vuex 下拥有 install 方法和 Store 类。即创建一个 Vuex 的模块,这个模块导出 install 方法和 Store 类。

install 方法

Vuex 是 Vue 的一个插件,所以需要实现 Vue 插件约定的 install 方 法。

Vue.use 内部会调用 Vuex 对象的 install 方法。

install作用:在 install 中把创建 Vue 根实例时传入的 store 对象注入到 Vue 实例的 $store 中。目的是,在所有组件中可以通过this.$store获取到 Vuex 中的仓库。

然而在 install 方法中无法拿到 Vue 的实例对象。

Vuex 中通过混入 beforeCreate 来获取 Vue 实例。

部分代码如下:

function install(Vue) {
  // 将Vue实例传递给一个局部变量,以便在函数范围内使用
  _Vue = Vue;
  // 通过混入beforeCreate来获取Vue实例,从而拿到选项中的store对象
  _Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        _Vue.prototype.$store = this.$options.store;
      }
    },
  });
}

其中,在给 Vue 混入 beforeCreate 钩子函数时,加了一个判断this.$options.store

目的是,

保证只在 main.js 文件中创建根 Vue 实例时执行一遍注入操作(_Vue.prototype.$store = this.$options.store)。在后续创建组件实例时,组件的选项 $options 中没有 router 所以不会再执行注入。

Store

首先 store 是一个类,它的构造函数接受一个对象作为参数,这个对象中的属性就是我们熟悉的 stategettersmutationsactions

  • 实现构造函数,接收 options
  • state 的响应式处理。
  • getterrs 的实现。
  • commitdispatch 方法。

注意:

下面代码对 getters 处理中:
其中this.getters = Object.create(null),此处不直接写this.getters = getters,是因为下面的代码中要方法 getters 中的 key 如果这么写的话,会导致 this.gettersgetters 指向同一个对象,当访问 getterskey 的时候,实际上就是访问 this.getterskey 会触发 key 属性的 get,会产生死递归。

部分代码如下:

class Store {
  constructor(options) {
    const { state = {}, getters = {}, mutations = {}, actions = {} } = options;

    this.state = _Vue.observable(state);

    // 此处不直接 this.getters = getters,会产生死递归
    this.getters = Object.create(null);
    Object.keys(getters).forEach((key) => {
      Object.defineProperty(this.getters, key, {
      	// 箭头函数 返回通过key在getters中获取到的方法的执行 结果
        get: () => getters[key](this.state), // 这里是state如何传到getters中的
      });
    });
	// mutations actions都是内部属性,不希望外部直接访问到
    this._mutations = mutations;
    this._actions = actions;
  }

  commit(type, payload) {
    this._mutations[type](this.state, payload);
  }

  dispatch(type, payload) {
    this._actions[type](this, payload);
  }
}

完整结构

Vue 中使用 Vuex 示例如下:
store–index.js

import Vue from 'vue' 
import Vuex from 'vuex' 
Vue.use(Vuex)
export default new Vuex.Store({
  state: { 
  	count: 0, 
  	msg: "Hello World" 
  },
  getters: {
    reverseMsg(state) {
      return state.msg.split("").reverse().join("");
    },
  },
  mutations: {
    increate(state, payload) {
      state.count += payload.num;
    },
  },
  actions: {
    increate(context, payload) {
      setTimeout(() => {
        context.commit("increate", { num: 5 });
      }, 2000);
    },
  },
});

myvuex–index.js

let _Vue = null;

class Store {
  constructor(options) {
    const { state = {}, getters = {}, mutations = {}, actions = {} } = options;

    this.state = _Vue.observable(state);

    // 此处不直接 this.getters = getters,会产生死递归
    this.getters = Object.create(null);
    Object.keys(getters).forEach((key) => {
      Object.defineProperty(this.getters, key, {
      	// 箭头函数 返回通过key在getters中获取到的方法的执行 结果
        get: () => getters[key](this.state), // 这里是state如何传到getters中的
      });
    });
	// mutations actions都是内部属性,不希望外部直接访问到
    this._mutations = mutations;
    this._actions = actions;
  }

  commit(type, payload) {
    this._mutations[type](this.state, payload);
  }

  dispatch(type, payload) {
    this._actions[type](this, payload);
  }
}

function install(Vue) {
  // 将Vue实例传递给一个局部变量,以便在函数范围内使用
  _Vue = Vue;
  // 通过混入beforeCreate来获取Vue实例,从而拿到选项中的store对象
  _Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        _Vue.prototype.$store = this.$options.store;
      }
    },
  });
}

// 导出模块
export default {
  Store,
  install,
};
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值