# 插件的用法

这里使用两个两个插件,一个是vuex 自带的 logger,一个是用于做持久化的 vuex-persist 。做持久化为什么不直接使用 localStorage 呢?这是因为直接用 localStorage 数据并不是响应式的。

安装 vuex-persist

npm install vuex-persist -S

具体代码如下:



 
 



 
 
 










 
 
 
 
































































import Vue from 'vue'
import Vuex from 'vuex'
import logger from 'vuex/dist/logger'
import VuexPersistence from 'vuex-persist'
// import Vuex from '@/vuex'


const vuexLocal = new VuexPersistence({
  storage: window.localStorage
})

// 会默认调用 Vuex 的 install 方法
// Vue.use方法的简单实现
// Vue.use = function(plugin, options) {
//   plugin.install(Vue, options)
// }
Vue.use(Vuex)

// Vuex是一个对象,里面有一个大写的Store和install方法
export default new Vuex.Store({
  plugins:[
    logger(),
    vuexLocal.plugin
  ],
  state: {
    count: 1,
    // 注意,如果state中的属性和模块同名,后面的会覆盖前面的,导致无法取到这个值
    a: 'a'
  },
  getters: {
    getCount(state) {
      return state.count + 1
    }
  },
  mutations: {
    changeCount(state, payload) {
      state.count += payload 
    }
  },
  actions: {
    changeCount({ commit }, payload) {
      setTimeout(() => {
        commit('changeCount', payload)
      }, 1000)
    }
  },
  modules: {
    a: {
      namespaced: true,
      state: {
        name: 'f',
        count: 18
      },
      mutations: {
        changeCount(state, payload) {
          state.count += payload 
        }
      },
      modules: {
        c: {
          namespaced: true,
          state: {
            name: 'c',
            count: 16
          },
          mutations: {
            changeCount(state, payload) {
              state.count += payload 
            }
          }
        }
      }
    },
    b: {
      namespaced: true,
      state: {
        name: 'g',
        count: 17
      },
      mutations: {
        changeCount(state, payload) {
          state.count += payload 
        }
      }
    }
  }
})

# 模拟logger插件



 



 
 
 
 
 
 
 
 
 















 
 
 

































































import Vue from 'vue'
import Vuex from 'vuex'
// import logger from 'vuex/dist/logger'
import VuexPersistence from 'vuex-persist'
// import Vuex from '@/vuex'

const logger = () => (store) => {
  let prevState = JSON.stringify(store.state)
  store.subscribe((mutation, state) => { // 监听变化,每次数据变化都会执行此方法
    console.log('prev', prevState)
    console.log(mutation)
    prevState = JSON.stringify(state)
    console.log('next', prevState)
  })
}

const vuexLocal = new VuexPersistence({
  storage: window.localStorage
})

// 会默认调用 Vuex 的 install 方法
// Vue.use方法的简单实现
// Vue.use = function(plugin, options) {
//   plugin.install(Vue, options)
// }
Vue.use(Vuex)

// Vuex是一个对象,里面有一个大写的Store和install方法
export default new Vuex.Store({
  plugins:[
    // 注意插件执行顺序
    vuexLocal.plugin,
    logger()
  ],
  state: {
    count: 1,
    // 注意,如果state中的属性和模块同名,后面的会覆盖前面的,导致无法取到这个值
    a: 'a'
  },
  getters: {
    getCount(state) {
      return state.count + 1
    }
  },
  mutations: {
    changeCount(state, payload) {
      state.count += payload 
    }
  },
  actions: {
    changeCount({ commit }, payload) {
      setTimeout(() => {
        commit('changeCount', payload)
      }, 1000)
    }
  },
  modules: {
    a: {
      namespaced: true,
      state: {
        name: 'f',
        count: 18
      },
      mutations: {
        changeCount(state, payload) {
          state.count += payload 
        }
      },
      modules: {
        c: {
          namespaced: true,
          state: {
            name: 'c',
            count: 16
          },
          mutations: {
            changeCount(state, payload) {
              state.count += payload 
            }
          }
        }
      }
    },
    b: {
      namespaced: true,
      state: {
        name: 'g',
        count: 17
      },
      mutations: {
        changeCount(state, payload) {
          state.count += payload 
        }
      }
    }
  }
})

# 模拟VuexPersistence




 


 
 
 
 
 
 
 
 
 
 
 
 
 




























































































import Vue from 'vue'
import Vuex from 'vuex'
// import logger from 'vuex/dist/logger'
// import VuexPersistence from 'vuex-persist'
// import Vuex from '@/vuex'

class VuexPersistence {
  constructor(storage) {
    this.storage = storage.storage
    this.localName = 'local'
  }
  plugin = (store) => {
    const localState = JSON.parse(this.storage.getItem(this.localName))
    localState && store.replaceState(localState)
    store.subscribe((mutation, state) => {
      this.storage.setItem(this.localName, JSON.stringify(state))
    })
  }
}

const logger = () => (store) => {
  let prevState = JSON.stringify(store.state)
  store.subscribe((mutation, state) => { // 监听变化,每次数据变化都会执行此方法
    console.log('prev', prevState)
    console.log(mutation)
    prevState = JSON.stringify(state)
    console.log('next', prevState)
  })
}

const vuexLocal = new VuexPersistence({
  storage: window.localStorage
})

// 会默认调用 Vuex 的 install 方法
// Vue.use方法的简单实现
// Vue.use = function(plugin, options) {
//   plugin.install(Vue, options)
// }
Vue.use(Vuex)

// Vuex是一个对象,里面有一个大写的Store和install方法
export default new Vuex.Store({
  plugins:[
    vuexLocal.plugin,
    logger()
  ],
  state: {
    count: 1,
    // 注意,如果state中的属性和模块同名,后面的会覆盖前面的,导致无法取到这个值
    a: 'a'
  },
  getters: {
    getCount(state) {
      return state.count + 1
    }
  },
  mutations: {
    changeCount(state, payload) {
      state.count += payload 
    }
  },
  actions: {
    changeCount({ commit }, payload) {
      setTimeout(() => {
        commit('changeCount', payload)
      }, 1000)
    }
  },
  modules: {
    a: {
      namespaced: true,
      state: {
        name: 'f',
        count: 18
      },
      mutations: {
        changeCount(state, payload) {
          state.count += payload 
        }
      },
      modules: {
        c: {
          namespaced: true,
          state: {
            name: 'c',
            count: 16
          },
          mutations: {
            changeCount(state, payload) {
              state.count += payload 
            }
          }
        }
      }
    },
    b: {
      namespaced: true,
      state: {
        name: 'g',
        count: 17
      },
      mutations: {
        changeCount(state, payload) {
          state.count += payload 
        }
      }
    }
  }
})

# 实现plugins






 
 
 
 
 
 


















 










 




























 












 
 
 
 
 
 
 
 
 





 











import { applyMixin } from './install'
import ModuleCollection from './module/module-collection'
import { forEachValue } from './utils'

export let Vue
// 动态获取最新的state
const getState = (store, path) => { // store.state 获取最新状态
  return path.reduce((rootState, current) => {
    return rootState[current]
  }, store.state)
}
const installModule = (store, path, module, rootState) => {  
  let namespaced = store._modules.getNamespace(path)
  console.log('namespaced', namespaced)

  // 将子模块的状态定义到根模块
  if (path.length > 0) {
    const parent = path.slice(0, -1).reduce((memo, current) => {
      return memo[current]
    }, rootState)
    // 这样添加的状态不是响应式的
    // parent[path[path.length - 1]] = module.state

    // 新增不存在的属性属性使用set,将其设置为响应式的
    Vue.set(parent, path[path.length - 1], module.state)
  }

  module.forEachMutation((mutation, key) => {
    store.mutations[namespaced + key] = store.mutations[namespaced + key] || []
    store.mutations[namespaced + key].push((payload) => mutation.call(store, getState(store, path), payload))
  })
  module.forEachAction((action, key) => {
    store.actions[namespaced + key] = store.actions[namespaced + key] || []
    store.actions[namespaced + key].push((payload) => action.call(store, store, payload))
  })
  module.forEachChildren((childModule, key) => {
    installModule(store, path.concat(key), childModule, rootState)
  })
  module.forEachGetters((gettersFn, key) => {
    store.wrapGetters[namespaced + key] = () => {
      return gettersFn.call(store, getState(store, path))
    }
  })
}

function resetStoreVM(store, state) {
  const computed = {}
  forEachValue(store.wrapGetters, (fn, key) => {
    computed[key] = fn
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key]
    })
  })
  store._vm = new Vue({
    data: {
      $$state: state
    },
    computed
  })
}

export class Store {
  constructor(options) {
    // 可能用户会有嵌套的module
    this._modules = new ModuleCollection(options)
    console.log('ddd', this._modules)
    this.mutations = {} // 将用户所有模块的mutation都放到这个对象中
    this.actions = {} // 将用户所有模块的action放到这个对象中
    this.getters = {}
    this._subscribes = []
    
    this.wrapGetters = {} // 用于临时存放所有的getters
    const state = options.state // 获取用户状态

    // 将用户所有模块的 mutation、action、state、getters 都放到对象中
    installModule(this, [], this._modules.root, state)
    resetStoreVM(this, state)
    console.log('this.state', this.state)
    console.log('this.getters', this.getters)
    console.log('this.mutations', this.mutations)
    console.log('this.actions', this.actions)

    // 逐个执行plugin并传入store,默认插件就会执行
    options.plugins.forEach(fn => fn(this))
  }
  subscribe(fn) {
    this._subscribes.push(fn)
  }
  replaceState(newState) {
    this._vm._data.$$state = newState
  }
  get state() {
    return this._vm._data.$$state
  }
  commit = (type, payload) => {
    this.mutations[type] && this.mutations[type].forEach(fn => fn(payload)) // commit后,mutation执行完毕,状态就更新了
    this._subscribes.forEach(fn => fn({ type, payload }, this.state))
  }
  dispatch = (type, payload) => {
    this.actions[type] && this.actions[type].forEach(fn => fn(payload))
  }
}

export const install = (_Vue) => {
  Vue = _Vue
  applyMixin(Vue)
}