手写vuex简版

template

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p @click="$store.commit('add')">counter: {{$store.state.counter}}</p>
    <p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p>
    <p>{{$store.getters.doubleCounter}}</p>
  </div>
</template>

store/index.js

import Vue from "vue";
import Vuex from "./zhen-vuex";

// this.$store
// this.$store.state.xxx
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    counter: 0,
  },
  mutations: {
    add(state) {
      // state从哪来?
      state.counter++;
    },
  },
  actions: {
    add({ commit }) {
      // 参数是什么,哪来的?
      setTimeout(() => {
        commit("add");
      }, 1000);
    },
  },
  getters: {
    doubleCounter(state) {
      return state.counter * 2;
    },
  },
});

zhen-vuex手写

//实现目标
// 1.插件:挂载$store
// 2.实现Store

let Vue; //首先保存Vue构造函数
class Store {
  // 把vuex.state都变成响应式.用defineReavtive只能定义.借助new Vue能对vuex.state全部进行响应式处理
  constructor(opotions) {
    this._mutations = opotions.mutations;
    this._actions = opotions.actions;
    this._wrappedGetters = opotions.getters;
    // 定义computed选项
    const computed = {};
    this.getters = {};
    const store = this; //保存this指向
    // opotions.getters => {doubleCouter(state){}}
    Object.keys(this._wrappedGetters).forEach((key) => {
      // 获取用户定义的getter
      const fn = store._wrappedGetters[key];
      // 转换为computed可以使用的无参数的形式
      computed[key] = function() {
        return fn(store.state);
      };
      // 为getters定义只读属性(用户只能访问getters)
      Object.defineProperty(store.getters, key, {
        get: () => store._vm[key],
      });
    });
    // this.state = new Vue({
    //   data: opotions.state,
    // });
    // 对上面改写成不对外暴露的形式
    // $$state是访问不到的,会被隐藏起来
    this._vm = new Vue({
      data: {
        $$state: opotions.state,
      },
      computed,
    });

    // 绑定commit、dispatch的上下文store实例
    this.commit = this.commit.bind(this);
    this.dispatch = this.dispatch.bind(this);
  }
  // 对this.state进行隐藏,并不想外界去修改它,通过get的方式
  get state() {
    // _data和$data两者是一样的,
    return this._vm._data.$$state;
  }
  set state(v) {
    console.error("不能对vuex中的state进行直接修改");
  }
  commit(type, payload) {
    const entry = this._mutations[type];
    if (!entry) {
      console.error("未知mutations类型");
    }
    entry(this.state, payload);
  }
  dispatch(type, payload) {
    const entry = this._actions[type];
    if (!entry) {
      console.error("未知actions类型");
    }
    entry(this, payload);
  }
}
function install(_Vue) {
  Vue = _Vue;
  // Vue.use(install)的执行时间在很靠前的,这个时候还获取不到Vuex实例中,所以要巧妙的运用到Vue.mixin的beforeCreate()方法获取并挂载Vuex
  // 全局混入(每个组件都会用到)
  // 全局混入目的:延迟下面逻辑到vuex已经创建完毕并且附加到选项上时才执行
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store;
      }
    },
  });
}
// 为什么要{ store, install }  Vue.use(Vuex);use的是Vuex.install//export default new Vuex.Store
export default { Store, install };
上一篇:用extend替代vuex的方案


下一篇:vuex的传参使用