实现一个简单的vuex

Posted mengyuhang4879

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现一个简单的vuex相关的知识,希望对你有一定的参考价值。

vuex的用法

html

 <div id="app">
    弟弟的年龄:{{$store.state.age}}
    哥哥的年龄:{{$store.getters.getAge}}
    <button @click="$store.commit(\'changeAge\',5)">五年后</button>
    <button @click="$store.dispatch(\'changeAge\',10)">十年后</button>
  </div>

store

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
//状态
  state: {
    age: 18
  },
 //相当于计算属性
  getters: {
    getAge(state) {
      return state.age + 10;
    }
  },
  //修改状态的方法
  mutations: {
    changeAge(state, payload) {
      state.age = state.age + payload;
    }
  },
  //解决mutations只有同步没有异步
  actions: {
    changeAge({ commit }, payload) {
      setTimeout(() => {
        commit("changeAge", payload);
      },1000);
    }
  }
});

main

import store from "./store";
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");

简单的实现

vuex/index

vuex/index 作为总出口 使用两种形式导出
export {} ===> import {Store} from \'vuex\'
export default ===> import Store from \'vuex\'

import { Store, install } from "./store";
export { Store, install };
export default {
  Store,
  install,
};
vuex/store

vuex/store.js这个文件为了方便将install方法和Store类写在一起

install

install方法:将new Vue({store}) 中的store利用Vue的minxin方法通过递归遍历使所有组件都可以用$store来获取到

let Vue;
export const install = (_Vue) => {
  Vue = _Vue;
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        this.$store = this.$options.store;
      } else if (this.$options.parent && this.$options.parent.$options.store) {
        this.$store = this.$options.parent.$options.store;
      }
    },
  });
};

Store

state 方法

实现了install方法之后我们发现这样实现state更为方便一些

export class Store {
  constructor(options) {
    this.state = options.state
    }
}

上面这种可以获取到 但是并没有将state进行双向数据绑定,state改变视图并不会发生改变,上面的install方法可以拿到全局的Vue,这样我们可以利用Vue中的observe来将state中的数据添加get和set方法

export class Store {
  constructor(options) {
    let state = options.state;
    this._vm = new Vue({
      data: {
      //$$为内部方法 不挂载在实例上
        $$state: state,
      },
    });
  }
  //取state这个值得时候会触发这个方法
  get state() {
    return this._vm._data.$$state;
  }
}
公共方法forEach的实现
export const forEach = (obj, fn) => {
  Object.keys(obj).forEach((v) => fn(v, obj[v]));
};

使用方法

forEach({ name: "孟", val: "01" }, (key, fn) => {
  console.log(key, fn);
});
//传入一个对象,获取到对象的每一个key和val
getters方法的实现

getters是一个对象 使用的时候$store.getters.getAge,是getAge执行后的结果

    this.getters = {};
    let computed = {};
    forEach(options.getters, (key, fn) => {
    //每次其他数据变化刷新页面都会进行没必要的获取getters中的数据,computed具有缓存的效果 数据不发生改变就不会触发相应的方法
      computed[key] = () => {
        return fn(this.state);
      };
      //给getter进行双向数据绑定
      Object.defineProperty(this.getters, key, {
      //computed是挂载在实例上的属性
        get: () => this._vm[key],
      });
    });
    this._vm = new Vue({
      data: {
        $$state: state,
      },
      computed,
    });
mutations实现

mutations是依据发布订阅模式先将每一个函数储存在事件池中,然后通过用户的一个派发动作使对应的事件池中的函数执行

 class Store {
  constructor(options) {
  this.mutations = {};
    forEach(options.mutations, (key, fn) => {
      this.mutations[key] = (payload) => fn(this.state,payload);
    });
   }
     commit = (key, payload) => {
    this.mutations[key](payload);
  };
  }
    
actions的实现
 class Store {
  constructor(options) {
 this.actions = {};
    forEach(options.actions, (key, fn) => {
      this.actions[key] = (payload) => fn(this, payload);
    });
 dispatch = (key, payload) => {
    this.actions[key](payload);
  };
  }

以上是关于实现一个简单的vuex的主要内容,如果未能解决你的问题,请参考以下文章

代码片段 - Golang 实现简单的 Web 服务器

vuex的原理以及实现

Vuex modules的简单使用,Vue状态管理多模块实现

vuex: 简单(弹窗)实现

手把手教你学vue-4(vuex)

VSCode自定义代码片段13——Vue的状态大管家