zoukankan      html  css  js  c++  java
  • vuex的实现

    源代码可以查看我的github:  https://github.com/Jasonwang911/TryHardEveryDay/tree/master/Vuex/vuex-resouce  欢迎star

    先描述一下vuex的使用:

    store.js

    import Vue from "vue";
    import Vuex from "./vuex/myVuex";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: {
        age: 20
      },
      getters: {
        // date 的 computed
        myAge(state) {
          return state.age + 10;
        }
      },
      mutations: {
        syncAdd(state, payload) {
          state.age += payload;
        },
        syncMinuts(state, payload) {
          state.age -= payload;
        }
      },
      actions: {
        asyncMinus({ commit }, payload) {
          setTimeout(() => {
            commit("syncMinuts", payload);
          }, 1000);
        }
      }
    });
    

      

    main.js中引用:

    import Vue from "vue";
    import App from "./App.vue";
    import router from "./router";
    import store from "./store";
    
    Vue.config.productionTip = false;
    
    new Vue({
      router,
      store, // 在每个实例上添加一个 $store 对象
      render: h => h(App)
    }).$mount("#app");
    

    先说这两点 

    1. Store是一个类

    2. Vue.use(Vuex);  

    首先建立一个类并导出,同时导出一个install的方法,这个方法接收一个参数 _Vue,即 vue实例

    let Vue
    
    class Store {
    
    }
    
    const install = _Vue => {
      Vue = _Vue          
    }
    
    export default {
      Store,
      install    
    }
    

      

    然后再main.js 中所作的就是讲store实例注册到vue的跟组件和所有的子组件上, 这里使用了Vue.mixin()的方法,在每个组件中注入$store,并在子组件中通过 this.$parents来拿到父组件的$store并添加到子组件的实例上

    const install = _Vue => {
      Vue = _Vue;
      // console.log(Vue);
      Vue.mixin({
        beforeCreate() {
          if (this.$options && this.$options.store) {
            // 根组件
            this.$store = this.$options.store;
          } else {
            this.$store = this.$parent && this.$parent.$store;
          }
        }
      });
    };
    

      

    先来看看state是怎么用的

    import Vue from "vue";
    import Vuex from "./vuex/myVuex";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: {
        age: 20
      },
    });

    在new Vuex.Store的实例的时候传入了一个对象,这个对象options

    然后我们添加state的这个属性

    class Store {
      constructor(options) {
        // options 是 new Vuex时注入的对象
        this._vm = options.state || {};
      }
      get state() {
        // store.state
        return this._vm;
      }
    }

    这里有一个问题,通过options获取的state并不是Observe状态的,并不能响应式的更新视图,如何做才能使state变成响应式的并触发视图的更新呢,也就是通过Vue的数据劫持进行包装转换,

    这里通过new Vue,并把state放入创建的Vue的data中来实现这个操作

    class Store {
      constructor(options) {
        // options 是 new Vuex时注入的对象
        this._vm = new Vue({
          data: {
            state: options.state
          }
        });
      }
      get state() {
        // store.state
        return this._vm.state;
      }
    }
    

     

    这样,$store.state就变成了响应式的状态了

    接下来,同理  getters,mutations, actions 也是通过options传入获取的

    import Vue from "vue";
    import Vuex from "./vuex/myVuex";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: {
        age: 20
      },
      getters: {
        // date 的 computed
        myAge(state) {
          return state.age + 10;
        }
      },
      mutations: {
        syncAdd(state, payload) {
          state.age += payload;
        },
        syncMinuts(state, payload) {
          state.age -= payload;
        }
      },
      actions: {
        asyncMinus({ commit }, payload) {
          setTimeout(() => {
            commit("syncMinuts", payload);
          }, 1000);
        }
      }
    });
    

      

    先来实现一下getters方法: 每一个getter方法其实都是getters的一个属性,但是这个属性返回了一个函数。属性可以返回函数的方法可以通过Object.definedProperty()中的get()来实现:

    class Store {
      constructor(options) {
        // options 是 new Vuex.Store时注入的对象
        // getters 拿到new Store的时候传入的getters
        let getters = options.getters || {};
        // 创建 Store 的 getters 属性
        this.getters = {};
        Object.keys(getters).forEach(getterName => {
          // 是个函数,但是返回的是个属性
          Object.defineProperty(this.getters, getterName, {
            get() {
              return getters[getterName](this.state);
            }
          });
        });
      }
      
    }
    

      

    这里其实只做了一件事情: 循环传入的options上的getters对象,并在用户调用getters中的每一个属性的时候返回一个getter函数并执行,

    同理,mutations和actions也是如此实现的,只不过各自多了一个commit和dispatch的方法。

    commit 和 dispatch 方法的原理就是通过参数type去对应的mutations和actions中查找对应的mutation或者action传入payload并执行

    dispatch = (type, payload) => {
      this.actions[type](payload);
    };
    commit = (type, payload) => {
      this.mutations[type](payload);
    };
    

      

    查看Vuex源码,作者巧妙的将这个通过对象key进行循环的方法封装成了一个forEach函数:

    const forEach = (obj, callback) => {
      Object.keys(obj).forEach(key => {
        callback(key, obj[key]);
      });
    };
    

     这个函数传入了一个对象和一个回调函数,通过对key的循环,执行了回调函数,并向回调函数中传入了循环出对象obj的key和value,整理后整个Store对象变成了如下:

    const forEach = (obj, callback) => {
      Object.keys(obj).forEach(key => {
        callback(key, obj[key]);
      });
    };
    
    class Store {
      constructor(options) {
        // options 是 new Vuex时注入的对象
        // this._s = options.state || {};
        // 将store中的状态变成可被观测的数据
        this._vm = new Vue({
          data: {
            state: options.state
          }
        });
        // getters 拿到new Store的时候传入的getters
        let getters = options.getters || {};
        // 创建 Store 的 getters 属性
        this.getters = {};
        forEach(getters, (getterName, fn) => {
          Object.defineProperty(this.getters, getterName, {
            get: () => {
              return fn(this.state);
            }
          });
        });
        // mutations
        let mutations = options.mutations || {};
        this.mutations = {};
        forEach(mutations, (mutationName, fn) => {
          this.mutations[mutationName] = payload => {
            fn(this.state, payload);
          };
        });
        // actions
        let actions = options.actions || {};
        this.actions = {};
        forEach(actions, (actionName, fn) => {
          this.actions[actionName] = payload => {
             fn(this, payload);
          };
        });
      }
      dispatch = (type, payload) => {
        this.actions[type](payload);
      };
      commit = (type, payload) => {
        this.mutations[type](payload);
      };
      get state() {
        return this._vm.state;
      }
    }
    

     

    以上基本实现了一个简单的vuex的基本流程,所有的源码可以在我的github上查看,后续会继续修改支持vuex的模块化。

  • 相关阅读:
    bzoj 1051: [HAOI2006]受欢迎的牛
    bzoj 1192: [HNOI2006]鬼谷子的钱袋
    一些动规水题
    USACO 2014 Open Silver Fairphoto
    USACO 2013 Nov Silver Pogo-Cow
    09day1
    09day2
    08day2
    08day1
    07day2
  • 原文地址:https://www.cnblogs.com/jasonwang2y60/p/11272259.html
Copyright © 2011-2022 走看看