手写Vuex

前言

        这是我的一篇学习笔记,内容中可能会存在一些写的或者理解的不太ok的地方,希望大家在发现时能不吝赐教,大家一起交流沟通,共同进步,噢耶!

Vuex是什么?

        Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

这个状态自管理应用包含以下几个部分:

  • state,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。

    手写Vuex_第1张图片

准备工作 

        1、使用vue-cli创建一个test项目

        2、安装vuex

vue add vuex

开发插件(引用官方文档)

        Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}

效果图:

手写Vuex_第2张图片

 全代码敬上

let Vue;

class Store {
  constructor(options) {
    // data响应式处理
    // this.$store.state.xx
    // 将state中的属性隐藏起来,让用户不能直接访问到,而是通过get方法来读取
    // vuex中的所有属性都是依赖于state的,我们只需要将state设置为响应式的数据即可
    // 这里也可以通过Vue.util.defineReactive设置为响应式数据,但源码中使用的是new Vue方式
    this._vm = new Vue({
      data: {
        $$state: options.state
      }
    })
    // 保存用户配置
    this._mutations = options.mutations || {}
    this._actions = options.actions || {}
    // 在这里必须改变this的指向,否则在store中使用时this会是undefined
    this.commit = this.commit.bind(this)
    this.dispatch = this.dispatch.bind(this)

    // defineProperty(this.getters, 'doubleCounter', {get(){}})
    // getters相当于state的计算属性,在页面上也是直接展示的,所以也需要做成响应式数据
    this._getters = options.getters || {}
    this.getters = {}
    Object.keys(this._getters).forEach(name=>{
        Object.defineProperty(this.getters,name,{
            get:()=>{
                return this._getters[name](this.state)
            }
        })
    })
  }

  get state() {
    return this._vm._data.$$state
  }

  set state(v) {
    console.error('你不能直接修改state中的属性');
    
  }
  
  commit(funName, params) {
    // 获取funName对应的mutation
    const fun = this._mutations[funName]
    if (!fun) {
      console.error(`找不到${funName}方法`);
    }

    fun(this.state, params)
  }
  
  dispatch(funName, params) {
    const fun = this._actions[funName]
    if (!fun) {
      console.error(`找不到${funName}方法`);
    }

    fun(this, params)
  }
  
}
function install(_Vue) {
  Vue = _Vue

  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}

export default { Store, install };

手写实现

        1、初始化:store、install

let Vue;
class Store {
     constructor(options = {}) {
        // 将state中的属性隐藏起来,让用户不能直接访问到,而是通过get方法来读取
        // vuex中的所有属性都是依赖于state的,我们只需要将state设置为响应式的数据即可
        // 这里也可以通过Vue.util.defineReactive设置为响应式数据,但源码中使用的是new Vue方式
         this._vm = new Vue({
             data: {
                 $$state:options.state
             }
         });
     }
     get state() { 
         return this._vm._data.$$state
     }
     set state(v) {
         console.error('你不能直接修改state中的属性');
     }
}
function install(_Vue) {
     Vue = _Vue;
     Vue.mixin({
         beforeCreate() {
             if (this.$options.store) {
                 Vue.prototype.$store = this.$options.store;
             }
         }
     });
}
export default { Store, install };

        2、实现commit

class Store {
     constructor(options = {}) {
         // 保存⽤户配置的mutations选项
         this._mutations = options.mutations || {}
         // 在这里必须改变this的指向,否则在store中使用时this会是undefined
         this.commit = this.commit.bind(this)
     }
     commit(funName, params) {
         // 获取funName对应的mutation
         const fun = this._mutations[funName]
         if (!params) {
             console.error(`找不到${funName}方法`);
             return
         }
         fun(this.state, params);
     }
}

        3、实现dispach

class Store {
     constructor(options = {}) {
         // 保存⽤户配置的actions选项
         this._actions = options.actions || {}
         // 在这里必须改变this的指向,否则在store中使用时this会是undefined
         this.dispatch= this.dispatch.bind(this)
     }
     dispatch(funName, params) {
        const fun = this._actions[funName]
        if (!fun) {
          console.error(`找不到${funName}方法`);
        }

        fun(this, params)
      }
}

        4、实现getters

        getters不同于commit和dispach,getters相当于vuex的计算属性

class Store {
     constructor(options = {}) {
        // vue2.0中的响应式实现是通过Object.defineProperty
        // defineProperty(this.getters, 'doubleCounter', {get(){}})
        this._getters = options.getters || {}
        this.getters = {}
        Object.keys(this._getters).forEach(name=>{
            Object.defineProperty(this.getters,name,{
                get:()=>{
                    return this._getters[name](this.state)
                }
            })
        })
     }
}

你可能感兴趣的:(造轮子,vue,学习笔记,vue,js)