Vuex是Vue官方提供的状态管理模式,以下是一个封装良好的Vuex状态管理库实现,包含模块化设计、持久化存储和常用功能封装。
store/
├── index.js # 入口文件,创建store实例
├── state.js # 根状态
├── mutations.js # 根 mutations
├── actions.js # 根 actions
├── getters.js # 根 getters
├── modules/ # 模块目录
│ ├── user.js # 用户模块
│ ├── app.js # 应用模块
│ └── ...
└── plugins/ # 插件目录
└── persistence.js # 持久化插件
store/index.js - 入口文件
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import user from './modules/user'
import app from './modules/app'
import persistence from './plugins/persistence'
// 注册Vuex
Vue.use(Vuex)
// 自动导入modules目录下的所有模块
const requireModule = require.context('./modules', false, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
const moduleName = fileName.replace(/(^\.\/)|(\.js$)/g, '')
modules[moduleName] = requireModule(fileName).default || requireModule(fileName)
})
// 创建store实例
const store = new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
...modules,
user,
app
},
plugins: [persistence] // 应用持久化插件
})
export default store
store/plugins/persistence.js - 持久化插件
/**
* Vuex持久化插件
* 将指定的state保存到localStorage或sessionStorage
*/
export default function persistencePlugin (store) {
// 初始化时从本地存储加载状态
const savedState = localStorage.getItem('vuex_state')
if (savedState) {
try {
store.replaceState({
...store.state,
...JSON.parse(savedState)
})
} catch (e) {
console.error('Failed to parse saved state', e)
}
}
// 订阅state变化,保存到本地存储
store.subscribe((mutation, state) => {
// 只保存需要持久化的模块
const stateToPersist = {
user: state.user,
app: {
theme: state.app.theme,
language: state.app.language
}
}
localStorage.setItem('vuex_state', JSON.stringify(stateToPersist))
})
}
store/modules/user.js - 用户模块示例
const state = {
token: '',
userInfo: null,
permissions: []
}
const mutations = {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_USER_INFO: (state, userInfo) => {
state.userInfo = userInfo
},
SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions
},
CLEAR_USER_STATE: (state) => {
state.token = ''
state.userInfo = null
state.permissions = []
}
}
const actions = {
// 登录
login({ commit }, userData) {
return new Promise((resolve, reject) => {
// 模拟API请求
setTimeout(() => {
const { username } = userData
const token = 'mock_token_' + Date.now()
commit('SET_TOKEN', token)
commit('SET_USER_INFO', { username, role: 'admin' })
commit('SET_PERMISSIONS', ['read', 'write', 'delete'])
resolve({ success: true, token })
}, 500)
})
},
// 退出登录
logout({ commit }) {
return new Promise(resolve => {
commit('CLEAR_USER_STATE')
resolve()
})
},
// 获取用户信息
getUserInfo({ commit, state }) {
return new Promise((resolve) => {
if (state.userInfo) {
resolve(state.userInfo)
return
}
// 模拟从服务器获取用户信息
setTimeout(() => {
const userInfo = {
username: 'admin',
name: 'Administrator',
avatar: 'https://picsum.photos/200/200',
role: 'admin'
}
commit('SET_USER_INFO', userInfo)
resolve(userInfo)
}, 300)
})
}
}
const getters = {
isAuthenticated: state => !!state.token,
hasPermission: state => (permission) => {
return state.permissions.includes(permission)
},
userAvatar: state => state.userInfo?.avatar || ''
}
export default {
namespaced: true, // 启用命名空间
state,
mutations,
actions,
getters
}
main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
store, // 注入store
render: h => h(App)
}).$mount('#app')
组件中使用示例
<template>
<div class="user-profile">
<div v-if="isAuthenticated">
<img :src="userAvatar" alt="User avatar" />
<p>{{ userInfo?.name }}</p>
<button @click="handleLogout">Logout</button>
</div>
<div v-else>
<button @click="handleLogin">Login</button>
</div>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions } from 'vuex'
export default {
computed: {
// 映射user模块的状态
...mapState('user', ['userInfo', 'token']),
// 映射user模块的getters
...mapGetters('user', ['isAuthenticated', 'userAvatar', 'hasPermission'])
},
methods: {
// 映射user模块的actions
...mapActions('user', ['login', 'logout', 'getUserInfo']),
async handleLogin() {
try {
const result = await this.login({ username: 'admin', password: '123456' })
console.log('Login success', result)
} catch (error) {
console.error('Login failed', error)
}
},
async handleLogout() {
await this.logout()
console.log('Logout success')
}
},
mounted() {
// 页面加载时获取用户信息
if (this.isAuthenticated) {
this.getUserInfo()
}
}
}
</script>
namespaced: true
避免模块间命名冲突require.context
自动导入模块,减少手动配置这种封装方式既保留了Vuex的核心功能,又提供了更好的可维护性和扩展性,适合中大型Vue项目使用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。