Vue
项目中使用Vuex
作为状态管理已经是比较通用的做法了,Vuex
本质上类似全局的变量存储,方便在所有Vue
组件中共享,而且也可以动态改变状态。
目前使用Vuex
可以把登录数据保存到localStorage
中,实现短时间内免登陆。
存储localStorage
参考:Vue项目集成vuex-persistedstate
但是Vuex
似乎没有考虑提供一个重置或者清空state
的方法,需要自己来实现。
清理登录数据
注销时需要清理store
比较麻烦,store
是在内存中,哪怕是删除localStorage
,也可能再次把内存中的store
数据写入localStorage
,造成注销失败。
直接删除localStorage
可以直接删除localStorage
,删除后还需要刷新页面,似乎体验不是很好,整个页面会刷新。
window.localStorage.removeItem(STORAGE_KEY)
window.location.reload()
重置store
还是考虑从store
下手,重置store
的思路如下:
- 在
store
初始化的时候把store
中的初始state
存下来 - 给
actions
和mutations
增加一个重置(__resetStoreState
)方法,并把重置方法名称保存到重置方法列表中 - 如果有子模块,递归处理子模块,重复第2步骤
- 提供一个外部访问的重置方法,具体逻辑就是把重置方法列表中的重置方法触发一下。
具体实现
具体代码如下(StoreHelper.js
),依赖lodash
库:
import cloneDeep from 'lodash/cloneDeep'
import store from '@/store'
import Vuex from 'vuex'
const TO_RESET_STORE_STATE_KEYS = [] // 需要清理的Key
const RESET_STORE_STATE_KEY = '__resetStoreState' // 内部清理方法名
/**
* store重置初始化,递归处理子模块,并把需要重置的key保存下来
*
* @param configData store数据
* @param excludeNames 不清理的模块名,有些数据可能需要在注销时也不清理
* @param parentModuleKey 模块名拼接,处理子模块
*/
export function $createStoreWithResetHandler (configData, excludeNames = [], parentModuleKey = '') {
const resetStoreKey = parentModuleKey ? `${parentModuleKey}/${RESET_STORE_STATE_KEY}` : RESET_STORE_STATE_KEY
TO_RESET_STORE_STATE_KEYS.push(resetStoreKey) // reset相关key存入数组中
if (configData.modules) {
Object.keys(configData.modules).forEach(moduleName => {
if (excludeNames.indexOf(moduleName) === -1) {
const module = configData.modules[moduleName]
const newParentModuleKey = parentModuleKey ? `${parentModuleKey}/${moduleName}` : moduleName
$createStoreWithResetHandler(module, excludeNames, newParentModuleKey)
}
})
}
if (configData.state) {
configData.mutations = configData.mutations || {}
configData.actions = configData.actions || {}
if (!configData.mutations[RESET_STORE_STATE_KEY]) {
const initialState = cloneDeep(configData.state)
configData.mutations[RESET_STORE_STATE_KEY] = state => Object.assign(state, cloneDeep(initialState))
}
if (!configData.actions[RESET_STORE_STATE_KEY]) {
configData.actions[RESET_STORE_STATE_KEY] = ({ commit }) => commit(RESET_STORE_STATE_KEY)
}
}
return configData
}
/**
* 重置store方法
*
* @returns Promise
*/
export function $resetStoreState () { // 需要重置的key已经存下来,循环key触发重置
const resetResults = TO_RESET_STORE_STATE_KEYS.map(resetKey => store.dispatch(resetKey))
return Promise.allSettled(resetResults)
}
/**
* 包装store,方便使用
*
* @param configData
* @param excludeNames
* @returns {Store<unknown>}
*/
export function $wrapStore (configData, excludeNames = []) {
return new Vuex.Store($createStoreWithResetHandler(configData, excludeNames))
}
/**
* 导出$resetStoreState方法,方便使用
* Vue.use(StoreHelper)
*/
export default {
install: (Vue, options = {}) => Object.assign(Vue.prototype, { $resetStoreState })
}
包装store搜集数据
包装store
搜集state
数据,以及需要触发reset
的相关方法
store.js
默认代码(去掉import
):
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {
Common: CommonStore,
Theme: ThemeStore
},
plugins: [createPersistedState()]
})
修改代码也比较简单,把new Vuex.Store
换成$wrapStore
,如果部分模块不要reset
,可以过滤掉:
Vue.use(Vuex)
Vue.use(StoreHelper)
export default $wrapStore({
state: {},
mutations: {},
actions: {},
modules: {
Common: CommonStore,
Theme: ThemeStore
},
plugins: [createPersistedState()]
}, ['Common']) // Common模块不要reset
触发store重置
在需要的地方触发一下重置,比如注销,然后跳转到登录页面即可
this.$resetStoreState().then(() => {
// 跳转到登录页面
})