vuex

vuex实践

Posted by SkioFox on May 18, 2018

vuex基本使用


  // store.js
    import Vue from 'vue'
    import Vuex from 'vuex'
    import module1 from './modules/module1'
    import module2 from './modules/module2'

    Vue.use(Vuex)
    export default new Vuex.Store({
      state: {
        count: 1
      },
      // 必须是同步的
      mutations: {
        increase(state){
          state.count+=1;
        }
      },
      // 异步的mutations,处理异步数据,比如处理与后端的请求
      actions: {
        // 获取到的时store实例,直接解构出state,commit使用, 同时还可以进行传参
        increaseAsync({state,commit},args){
          // 异步处理很多时候需要得到异步结果,返回一个Promise对象
          // return new Promise(resolve=>{

          // })
        }
      },
      // 类似于组件中的computed,对state中数据进行加工
      getters: {
        money: state=>{
          return state.count+''
        }
      },
      // 当store中数据和操作过多,可以进行分模块
      modules: {
        module1,
        module2
      },
    })

  // page.vue
  <template>
    <button @click=incAsync() >increaseAsync</button>
    <button @click=inc() >increase</button>
    <!-- 
    <p></p>
    <p></p>
    -->
    <!-- 使用map帮助方法后-->
    <p>8</p>
    <p></p>
  </template>
  <script>
  // 引入vuex的帮助方法mapState用于映射状态=>mapState是个函数,返回的是一个对象
  import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
    export default {
      methods: {
        // increase(){
        //   // 执行mutations里面的increase方法
        //   this.$store.commit('increase');
        // },
        // incAsync(){
        //   // 执行mutations里面的increase方法
        //   this.$store.dispatch('increaseAsync',args);
        // }
        // 当在store中的actions中使用返回Promise对象时这里就能使用async/await进行异步处理
        // async incAsync(){
        //   // await拿到返回的异步结果然后处理
        //   await this.$store.dispatch('increaseAsync',args);
        // }
        // 引入对应map方法后
        ...mapMutations(['increase']),
        ...mapActions(['increaseAsync']),
        inc(){
          this.increase();
        },
        incAsyc(){
          this.increaseAsync(args);
        }
      },
      computed: {
        // 因为mapState方法返回的是一个对象,所以需要解构出来,相当于
        // {count: this.$store.state.count},这时count就变成了计算属性,可以直接使用
        ...mapState(['count']),
        ...mapGetters(['money'])
        // 本质就是将状态声明为组件中的计算属性,一个组件需要获取多个状态时方便使用
        ...mapState({
          count:state=>state.count+""
        })
      }
    }
  </script>
      const store =new Store({
        state:{
          token: localStorage.getItem("token") || "",
          cart: JSON.parse(localStorage.getItem("cart")) || [
        },
        mutation:{

        },
        actions:{

        }
      })
        // 订阅store变化
      store.subscribe((mutation, state) => {
        switch (mutation.type) {
          case "setToken":
            localStorage.setItem("token", JSON.stringify(state.token));
            break;
          case "addCart":
            localStorage.setItem("cart", JSON.stringify(state.cart));
            break;
        }
      });    
    export default store;

vuex原理解析

  // Vue.use(Vuex),这是vue安装插件的机制,需要Vuex对外暴露一个install方法,会把Vue传递给install这个函数

  // 在vue.use的源码中 /src/core/global-api/use.js

  // 其实就是把传递插件的install方法执行一下,存储在一个插件数组中, 传递Vue进去,我们可以利用这个机制,对Vue本身进行扩展

  // mini-vuex

let Vue;
function install (_Vue) {
  Vue = _Vue;
  function vuexInit () {
    var options = this.$options;
    // store injection
    if (options.store) {
      this.$store = typeof options.store === 'function'
        ? options.store()
        : options.store;
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store;
    }
  }
  Vue.mixin({ beforeCreate: vuexInit });
}

const Store = function Store (options = {}) {
  const {state = {}, mutations={}, getters={}} = options
  const computed = {}
  const store = this
  store.getters = {};
  for (let [key, fn] of Object.entries(getters)) {
    computed[key] = function () { return fn(store.state, store.getters); };
    Object.defineProperty(store.getters, key, {
      get: function () { return store._vm[key]; },
    });
  }
  this._vm = new Vue({
    data: {
      $$state: state
    },
    computed,
  })
  this._mutations = mutations
}
Store.prototype.commit = function(type, payload){
  if(this._mutations[type]) {
    this._mutations[type](this.state, payload)
  }
}
Object.defineProperties(Store.prototype, { 
  state: { 
    get: function(){
      return this._vm._data.$$state
    } 
  }
});
export default {Store, install}