github,blog

Vuex

Vuex集中式存储管理利用的所有组件的状态,并以相应的规定保障状态以可预测的形式发生变化。

装置Vuex

vue add vuex

外围概念

  • state:状态、数据
  • mutations:更改状态的函数
  • action:异步操作
  • store:蕴含以上概念的容器

状态 - state

state保留利用状态

export default new Vuex.Store({  state: {    counter: 0  }})
<h1>  {{$store.state.counter}}</h1>

状态变更 - mutations

mutations用于批改状态

export default new Vuex.Store({  mutations:{    add(state){      state.counter++    }  }})
<h1 @click="$store.commit('add')">  {{$store.state.counter}}</h1>

派生状态 - getters

state派生进去新状态,相似计算属性

export default new Vuex.Store({  getters:{    doubleCounter(state){      return state.counter * 2;    }  }})
<h1>  {{$store.getters.doubleCounter}}</h1>

动作 - actions

增加业务逻辑,相似于controller

export default new Vuex.Store({  actions:{    add({commit}){      setTimeout(() => commit('add'), 1000);    }  }})
<h1 @tap="$store.dispatch('add')">  {{$store.state.counter}}</h1>

Vuex原理解析

任务分析

  • 实现插件

    • 实现Store类

      • 维持一个响应式状态state
      • 实现commit()
      • 实现dispatch()
      • 实现getters
    • 挂载$store

创立新的插件

Vue2.x我的项目中的src门路下,复制一份store文件,重命名为ou-store

而后在ou-store门路下新建一个ou-vuex.js文件,并将index.js文件中的Vuex引入改为ou-vuex.js

import Vuex from './ou-vuex'

同时将main.js中的router引入也批改一下。

import router from './ou-vuex'

创立vue的插件

回头看一下store/index.js,首先是应用Vue.use()注册了Vuex,而后再实例化了Vuex.Store这个类,因而Vuex这个对象里含有一个install办法以及一个Store的类。

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({    ...})

因而咱们来创立一个新的Vuex插件。

let Vue;    // 保留Vue的构造函数,插件中须要用到class Store {}function install(_Vue) {    Vue = _Vue;}export default {Store, install};

挂载$store

let Vue;    // 保留Vue的构造函数,插件中须要用到class Store {}function install(_Vue) {    Vue = _Vue;    Vue.mixin({        beforeCreate() {            // 挂载$store            if(this.$options.store){                Vue.prototype.$store = this.$options.store;     // vm.$store            }        }    })}export default {Store, install};

实现响应式保留state数据

因为state是一个对象,咱们能够应用new Vue()state转换为一个响应式数据进行保存起来。

其次,咱们不能显式去保留这个state,裸露给里面,因而咱们能够应用getset去保留。

class Store {    /*    * options:    *   state    *   mutations    *   actions    *   modules    *   getters    * */    constructor(options = {}) {        // data响应式解决        this._vm = new Vue({               data: {                $$state: options.state    // 通过this._vm._data.$$state 或 this._vm.$data.$$state 获取            }        });    }    // 获取state    get state() {        return this._vm._data.$$state;    }    // 不可设置state    set state(v) {        console.error('please use replaceState to reset state');    }}

实现commit办法

当咱们应用commit办法时,都是$store.commit(type,payload),第一个参数即mutationstype值,第二个是payload负载,而对应mutation办法的参数为statepayload,因而咱们来实现:

class Store {    constructor(options = {}) {        this._vm = new Vue({            data: {                $$state: options.state            }        });        // 保留用户配置的mutations选项        this._mutations = options.mutations;    }    get state() {        return this._vm._data.$$state;    }    set state(v) {        console.error('please use replaceState to reset state');    }    commit(type, payload) {        // 获取type对应的mutation        const entry = this._mutations[type]        if(!entry) {            console.error(`unknown mutation type : ${type}`);            return ;        }        // 传递state和payload给mutation        entry(this.state, payload)    }}

实现dispatch办法

dispatch办法跟commit办法大同小异,不同之处在于dispatch调用的是action异步函数,而action的参数为contextpayloadpayload咱们能够通过dispatch的参数获取到,而context执行上下文其实就是实例中的this

action是用来解决异步函数的,因而咱们须要对dispatch办法进行this绑定;同时,action办法中有可能会调用到commit办法,因而咱们也须要对commit办法进行this绑定。

class Store {    constructor(options = {}) {        this._vm = new Vue({            data: {                $$state: options.state             }        });        // 保留用户配置的mutations选项和actions选项        this._mutations = options.mutations;        this._actions = options.actions;        // 将commit和dispatch绑定this,        this.commit = this.commit.bind(this);        this.dispatch = this.dispatch.bind(this);    }    get state() {        return this._vm._data.$$state;    }    set state(v) {        console.error('please use replaceState to reset state');    }    commit(type, payload) {        const entry = this._mutations[type]        if(!entry) {            console.error(`unknown mutation type : ${type}`);            return ;        }        entry(this.state, payload)    }    dispatch(type, payload) {        // 获取用户编写的type对应的action        const entry = this._actions[type];        if(!entry) {            console.error(`unknown action type : ${type}`)        }        // 异步后果解决经常须要返回Promise        return entry(this, payload)    }}

实现getters派生状态

当咱们定义getters状态时,实际上是定义了一个function

getters: {   doubleCounter(state) {     return state.counter * 2;   }},

而应用getters中某一个派生状态时,实际上是失去一个值,也就是这个function的返回值。

<h4>double count: {{$store.getters.doubleCounter}}</h4>

这其实就有点像对象中的get属性,因而咱们能够应用Object.defineProperty()来实现getters

class Store {    constructor(options = {}) {        this._vm = new Vue({            data: {                $$state: options.state               }        });        this._mutations = options.mutations;        this._actions = options.actions;        this.commit = this.commit.bind(this);        this.dispatch = this.dispatch.bind(this);        // 初始化getters,默认为一个空对象        this.getters = {};        // 遍历options.getters        for (const key in options.getters) {            const self = this;            Object.defineProperty(                this.getters,                key,   // key名                {                    get() {                          // 调用对应的函数,第一个参数为state,将后果返回                        return options.getters[key](self._vm._data.$$state)                       }                }            )        }    }}