Vuex 项目实战完整模板

0 阅读7分钟

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 最佳实践(避坑指南)

  1. 模块化必须开启 namespaced: true,避免不同模块的方法、数据名称冲突。

  2. 严格遵循“只能通过 Mutations 修改 State”,禁止在组件或 Actions 中直接修改 State,便于调试和维护。

  3. 所有异步操作(接口请求、定时器等)必须放在 Actions 中,Mutations 只做同步操作。

  4. Vuex 只存储“多组件共享的数据”(如 Token、用户信息、全局配置),组件私有数据(如单个组件的输入框值)无需放入 Vuex。

  5. 关键数据(如 Token)需做 localStorage 持久化,避免页面刷新后数据丢失。

  6. 路由守卫配合 Vuex 做权限控制,统一管理页面访问权限,避免重复判断。

十一、备注

  1. 本文档所有代码均为可运行版本,实际项目中需替换接口地址(baseURL、接口路径)为后端真实地址。

  2. 组件(Login.vue、Home.vue、User.vue)需自行创建,代码可直接复制使用,样式可根据项目需求调整。

  3. 若使用 Vue3,需替换为 Vuex4 或 Pinia(Vue3 推荐使用 Pinia),可联系获取对应版本模板。

(注:文档部分内容可能由 AI 生成)