// src/store/index.js
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({
strict: true,
plugins:[
vuexLocal.plugin,
logger()
],
state: {
count: 1,
// 注意,如果state中的属性和模块同名,后面的会覆盖前面的,导致无法取到这个值
a: 'a'
},
getters: {
getCount(state) {
return state.count + 1
}
},
mutations: {
changeCount(state, payload) {
// state.count += payload
// 设置 strict: true 后不能在 mutations 中异步修改 state
setTimeout(() => {
state.count += payload
}, 1000);
}
},
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
}
}
}
}
})
// src/vuex/store.js
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
store._withCommiting(() => {
// 新增不存在的属性属性使用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
})
if (store.strict) {
store._vm.$watch(() => store._vm._data.$$state, () => {
// 如果断言为false,则将一个错误消息写入控制台。如果断言是 true,没有任何反应
console.assert(store._commiting, '在mutation之外修改了状态')
}, { sync: true, deep: true }) // watcher执行是异步的,同步执行需要配置sync属性
}
}
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.strict = options.strict
this._commiting = false
this._withCommiting = function(fn) {
let commiting = this.commiting
this._commiting = true
fn() // 修改状态的逻辑
this._commiting = commiting
}
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._withCommiting(() => {
this._vm._data.$$state = newState
})
}
get state() {
return this._vm._data.$$state
}
commit = (type, payload) => {
this._withCommiting(() => {
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)
}
← 插件的用法