Vuex 项目实战完整模板
一、文档说明
本文档为企业级 Vue2 + Vuex3 实战标准模板,所有代码可直接复制到项目中运行,包含核心功能:Vuex 模块化规范、用户登录与Token持久化、用户信息与权限管理、Axios请求封装、路由权限守卫、组件内标准使用方式。
适配PDF排版要求,层级清晰、代码块独立、重点内容突出,可直接复制至WPS、Word等编辑器,导出为PDF文件使用。
二、环境准备与依赖安装
本模板适配 Vue2 版本,对应 Vuex3,需先安装以下依赖:
# 安装 Vuex3(Vue2 专用)和 Axios(接口请求)
npm install vuex@3 axios --save
三、项目目录结构
请按照以下目录结构创建文件,确保代码引入路径正确(核心目录集中在 src 文件夹下):
src/
├── store/ # Vuex 核心目录
│ ├── index.js # Vuex 入口文件(组装模块)
│ └── modules/ # 模块化拆分目录
│ ├── user.js # 用户模块(登录、信息、Token、权限)
│ └── app.js # 全局配置模块(侧边栏、主题)
├── router/
│ └── index.js # 路由配置 + 全局权限守卫
├── api/
│ └── user.js # 用户相关接口封装
├── utils/
│ └── request.js # Axios 封装(请求/响应拦截器)
└── main.js # 项目入口文件(挂载 Vuex、Router)
四、Vuex 核心配置(重点)
4.1 store/index.js(Vuex 入口文件)
作用:引入 Vuex、注册各个模块,统一暴露 Store 实例,供 main.js 挂载。
import Vue from 'vue'
import Vuex from 'vuex'
// 引入各个模块
import user from './modules/user'
import app from './modules/app'
// 安装 Vuex 插件
Vue.use(Vuex)
// 导出 Store 实例
export default new Vuex.Store({
modules: {
user, // 注册用户模块
app // 注册全局配置模块
}
})
4.2 store/modules/user.js(用户模块,最常用)
核心功能:管理用户 Token、用户信息、登录/退出/获取用户信息等操作,包含 State、Getters、Mutations、Actions 完整配置,开启命名空间避免冲突。
// 引入用户相关接口(后续会配置)
import { login, getUserInfo } from '@/api/user'
// 1. State:存储用户相关全局数据
const state = {
token: localStorage.getItem('token') || '', // Token 持久化(刷新不丢失)
userInfo: {}, // 存储用户详细信息
roles: [] // 存储用户权限角色(用于权限控制)
}
// 2. Getters:对 State 数据进行加工(类似组件的 computed)
const getters = {
isLogin: (state) => !!state.token, // 判断是否登录(转化为布尔值)
userId: (state) => state.userInfo.id || '', // 获取用户ID(默认空字符串)
userName: (state) => state.userInfo.name || ''// 获取用户名(默认空字符串)
}
// 3. Mutations:唯一修改 State 的地方(必须同步操作)
const mutations = {
// 保存 Token
SET_TOKEN(state, token) {
state.token = token
localStorage.setItem('token', token) // 持久化到本地存储
},
// 保存用户信息
SET_USER_INFO(state, info) {
state.userInfo = info
state.roles = info.roles || [] // 同步存储用户角色
},
// 退出登录:清空用户数据
CLEAR_USER(state) {
state.token = ''
state.userInfo = {}
state.roles = []
localStorage.removeItem('token') // 清除本地存储的 Token
}
}
// 4. Actions:处理异步操作(如接口请求),通过 commit 调用 Mutations
const actions = {
// 登录操作(异步)
async login({ commit }, userData) {
const res = await login(userData) // 调用登录接口
commit('SET_TOKEN', res.token) // 提交 Mutations 保存 Token
return res // 返回接口结果,供组件使用
},
// 获取用户信息(异步)
async getUserInfo({ commit }) {
const res = await getUserInfo() // 调用获取用户信息接口
commit('SET_USER_INFO', res) // 提交 Mutations 保存用户信息
return res
},
// 退出登录(同步,也可放在 Mutations,此处统一放在 Actions 便于管理)
logout({ commit }) {
commit('CLEAR_USER') // 调用 Mutations 清空用户数据
}
}
// 导出模块,开启命名空间(必须开启,避免模块间方法/数据冲突)
export default {
namespaced: true,
state,
getters,
mutations,
actions
}
4.3 store/modules/app.js(全局配置模块)
作用:管理全局公共配置(如侧边栏状态、主题切换),可根据项目需求扩展。
// State:全局配置数据
const state = {
sidebarOpen: true, // 侧边栏默认开启
theme: 'light' // 默认主题(亮色)
}
// Mutations:修改全局配置(同步)
const mutations = {
// 切换侧边栏状态(打开/关闭)
TOGGLE_SIDEBAR(state) {
state.sidebarOpen = !state.sidebarOpen
},
// 设置主题
SET_THEME(state, val) {
state.theme = val
}
}
// Actions:暂无异步操作,留空可后续扩展
const actions = {}
// 导出模块,开启命名空间
export default {
namespaced: true,
state,
mutations,
actions
}
五、接口与请求封装
统一封装 Axios,处理请求拦截(添加 Token)、响应拦截(处理 401 未登录等异常),同时封装用户相关接口,便于维护。
5.1 api/user.js(用户接口封装)
集中管理用户相关接口,避免接口地址分散在各个组件中,便于后续修改。
// 引入封装好的 Axios 实例
import request from '@/utils/request'
// 登录接口(POST 请求,传递用户名、密码)
export function login(data) {
return request({
url: '/login', // 接口地址(实际项目替换为后端真实地址)
method: 'post', // 请求方式
data // 请求参数(用户名、密码等)
})
}
// 获取用户信息接口(GET 请求,需要 Token 授权)
export function getUserInfo() {
return request({
url: '/user/info',// 接口地址(实际项目替换为后端真实地址)
method: 'get' // 请求方式
})
}
5.2 utils/request.js(Axios 封装)
核心:创建 Axios 实例,配置请求基础路径、超时时间,添加请求/响应拦截器,统一处理 Token 和异常。
import axios from 'axios'
import store from '@/store' // 引入 Vuex Store,用于获取 Token、退出登录
// 创建 Axios 实例
const service = axios.create({
baseURL: '/api', // 接口基础路径(实际项目替换为后端接口前缀)
timeout: 10000 // 超时时间(10秒)
})
// 1. 请求拦截器:发送请求前,给请求头添加 Token(授权用)
service.interceptors.request.use(
(config) => {
const token = store.state.user.token // 从 Vuex 中获取 Token
if (token) {
// 添加 Token 到请求头(格式根据后端要求调整,此处为 Bearer 格式)
config.headers.Authorization = `Bearer ${token}`
}
return config // 返回配置好的请求
},
(error) => {
// 请求失败(如网络异常),返回错误
return Promise.reject(error)
}
)
// 2. 响应拦截器:接收响应后,统一处理异常(如 401 未登录)
service.interceptors.response.use(
(res) => res.data, // 直接返回响应体(简化组件中获取数据的操作)
(error) => {
// 401 状态码:未登录(Token 过期、无效)
if (error.response?.status === 401) {
store.dispatch('user/logout') // 调用退出登录,清空用户数据
location.reload() // 刷新页面,跳转到登录页
}
// 返回错误,供组件捕获处理
return Promise.reject(error)
}
)
// 导出封装好的 Axios 实例
export default service
六、路由配置与权限守卫
配置项目路由,添加全局路由守卫,实现“未登录跳转登录页、已登录不允许访问登录页、已登录自动获取用户信息”的权限控制逻辑。
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '@/store' // 引入 Vuex Store,用于判断登录状态
// 安装 VueRouter 插件
Vue.use(VueRouter)
// 配置路由规则
const routes = [
{
path: '/login', // 登录页路径
component: () => import('@/views/Login') // 懒加载登录组件(优化性能)
},
{
path: '/', // 首页路径
component: () => import('@/views/Home'), // 懒加载首页组件
meta: { requiresAuth: true } // 标记:需要登录才能访问
},
{
path: '/user', // 用户中心路径
component: () => import('@/views/User'), // 懒加载用户中心组件
meta: { requiresAuth: true } // 标记:需要登录才能访问
}
]
// 创建路由实例
const router = new VueRouter({ routes })
// 全局路由守卫(每次跳转路由前执行)
router.beforeEach(async (to, from, next) => {
// 1. 获取 Token,判断是否登录
const hasToken = store.state.user.token
// 2. 未登录:只能访问登录页,其他页面跳转登录页
if (!hasToken) {
if (to.path === '/login') return next() // 访问登录页,放行
return next('/login') // 访问其他页,跳转登录页
}
// 3. 已登录:不允许访问登录页,跳转首页
if (to.path === '/login') return next('/')
// 4. 已登录,但未获取用户信息(如页面刷新),自动获取用户信息
const hasUser = Object.keys(store.state.user.userInfo).length
if (!hasUser) {
await store.dispatch('user/getUserInfo') // 调用接口获取用户信息
}
// 5. 所有校验通过,放行
next()
})
// 导出路由实例
export default router
七、项目入口挂载(main.js)
将 Vuex Store 和 Router 挂载到 Vue 实例,使整个项目可以使用 Vuex 和路由功能。
import Vue from 'vue'
import App from './App.vue'
import store from './store' // 引入 Vuex Store
import router from './router'// 引入 Router
// 关闭 Vue 生产环境提示
Vue.config.productionTip = false
// 创建 Vue 实例,挂载 Store 和 Router
new Vue({
store, // 挂载 Vuex
router, // 挂载 Router
render: h => h(App) // 渲染根组件 App
}).$mount('#app') // 挂载到页面 #app 元素
八、组件内使用 Vuex 示例(实战常用)
以下为组件内使用 Vuex 的标准写法,使用辅助函数(mapState、mapGetters 等)简化代码,提高开发效率。
8.1 登录页面(Login.vue)
功能:实现用户名、密码输入,调用登录接口,登录成功后跳转首页。
<template>
<div class="login-container">
<!-- 用户名输入框 -->
<input
v-model="username"
placeholder="请输入用户名"
class="login-input"
/>
<!-- 密码输入框 -->
<input
v-model="password"
placeholder="请输入密码"
type="password"
class="login-input"
/>
<!-- 登录按钮 -->
<button @click="handleLogin" class="login-btn">登录</button>
</div>
</template>
<script>
// 引入 Vuex 辅助函数 mapActions(用于调用 Actions)
import { mapActions } from 'vuex'
export default {
data() {
return {
username: '', // 用户名
password: '' // 密码
}
},
methods: {
// 映射 user 模块的 login 方法(简化调用)
...mapActions('user', ['login']),
// 登录点击事件
async handleLogin() {
try {
// 调用登录接口(传递用户名、密码)
await this.login({
username: this.username,
password: this.password
})
// 登录成功,跳转首页
this.$router.push('/')
} catch (err) {
// 登录失败,打印错误信息(可根据需求添加提示)
console.log('登录失败:', err)
}
}
}
}
</script>
8.2 首页/头部组件(Home.vue)
功能:展示用户信息、退出登录、切换侧边栏状态,演示多模块(user、app)的使用。
<template>
<div class="home-header">
<!-- 展示用户信息(登录状态下显示) -->
<div class="user-info" v-if="isLogin">
欢迎您,{{ userName }}
<button @click="handleLogout" class="logout-btn">退出登录</button>
</div>
<!-- 侧边栏状态展示与切换 -->
<div class="sidebar-control">
侧边栏状态:{{ sidebarOpen ? '开启' : '关闭' }}
<button @click="toggleSidebar" class="sidebar-btn">切换侧边栏</button>
</div>
</div>
</template>
<script>
// 引入 Vuex 辅助函数(多模块使用)
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
computed: {
// 映射 user 模块的 state(userInfo)
...mapState('user', ['userInfo']),
// 映射 user 模块的 getters(isLogin、userName)
...mapGetters('user', ['isLogin', 'userName']),
// 映射 app 模块的 state(sidebarOpen)
...mapState('app', ['sidebarOpen'])
},
methods: {
// 映射 user 模块的 actions(logout)
...mapActions('user', ['logout']),
// 映射 app 模块的 mutations(TOGGLE_SIDEBAR)
...mapMutations('app', ['TOGGLE_SIDEBAR']),
// 退出登录事件
handleLogout() {
this.logout() // 调用退出登录方法
this.$router.push('/login') // 跳转登录页
},
// 切换侧边栏状态
toggleSidebar() {
this.TOGGLE_SIDEBAR() // 调用 mutations 方法
}
}
}
</script>
九、Vuex 原始调用方式(备用)
若不想使用辅助函数,可直接通过 $store 调用 Vuex 的数据和方法(适合简单场景,代码相对繁琐)。
// 1. 获取 State 数据
this.$store.state.user.token // 获取 user 模块的 token
this.$store.state.app.sidebarOpen // 获取 app 模块的侧边栏状态
// 2. 获取 Getters 加工后的数据
this.$store.getters['user/isLogin'] // 获取 user 模块的 isLogin
// 3. 提交 Mutations(同步修改 State)
this.$store.commit('user/SET_TOKEN', 'xxx') // 调用 user 模块的 SET_TOKEN
this.$store.commit('app/TOGGLE_SIDEBAR') // 调用 app 模块的 TOGGLE_SIDEBAR
// 4. 分发 Actions(异步操作)
this.$store.dispatch('user/login', { username, password }) // 调用登录
this.$store.dispatch('user/logout') // 调用退出登录
十、Vuex 最佳实践(避坑指南)
-
模块化必须开启
namespaced: true,避免不同模块的方法、数据名称冲突。 -
严格遵循“只能通过 Mutations 修改 State”,禁止在组件或 Actions 中直接修改 State,便于调试和维护。
-
所有异步操作(接口请求、定时器等)必须放在 Actions 中,Mutations 只做同步操作。
-
Vuex 只存储“多组件共享的数据”(如 Token、用户信息、全局配置),组件私有数据(如单个组件的输入框值)无需放入 Vuex。
-
关键数据(如 Token)需做 localStorage 持久化,避免页面刷新后数据丢失。
-
路由守卫配合 Vuex 做权限控制,统一管理页面访问权限,避免重复判断。
十一、备注
-
本文档所有代码均为可运行版本,实际项目中需替换接口地址(baseURL、接口路径)为后端真实地址。
-
组件(Login.vue、Home.vue、User.vue)需自行创建,代码可直接复制使用,样式可根据项目需求调整。
-
若使用 Vue3,需替换为 Vuex4 或 Pinia(Vue3 推荐使用 Pinia),可联系获取对应版本模板。
(注:文档部分内容可能由 AI 生成)