粉粉蕉的笔记本粉粉蕉的笔记本
  • JAVA

    • 代码笔记
    • Java8实战
    • 分布式事务实战(Seata)
    • 模板引擎(FreeMarker)
    • SpringSecurity
    • Maven
  • PYTHON

    • 概述
    • python3
    • python3(菜鸟教程)
    • pandas
    • numpy
    • matplotlib
  • 中间件

    • Kafka
    • RocketMQ
    • Redis
    • MongoDB
    • Elastic Search
  • 数据库

    • Mysql
  • 前端

    • HTML
    • CSS
    • Javascript
    • Vue2学习笔记
    • Vue3学习笔记
  • 设计模式
  • 大数据

    • 概览
    • Hadoop
    • Hive
  • 机器学习

    • 机器学习概览
  • openclaw实战
  • claudecode实战
  • RAG
  • 拟人类Agent
  • linux命令速查
  • windows命令速查
  • Docker笔记
  • kubernetes学习笔记
  • kubernetes实操笔记
  • 运维工具大全
  • git操作宝典
  • 概率论
  • 线性代数
  • 统计学
  • 金融知识学习
  • 聚宽
  • 因子分析
  • 后端

    • JAVA基础
    • JAVA多线程
    • JVM
    • 分布式相关
    • 数据库
  • 前端

    • HTML
    • CSS
    • JAVASCRIPT
    • VUE3
    • 网络
    • 前端工程化
    • nodejs
  • AI

    • RAG
  • 健身

    • 笔记
    • 训练计划
  • 读书笔记

    • 《深度学习》
  • 其他

    • RSS
    • 资源导航
    • 医保
    • 装修攻略
我也想搭建这样的博客!
🚋开往
  • JAVA

    • 代码笔记
    • Java8实战
    • 分布式事务实战(Seata)
    • 模板引擎(FreeMarker)
    • SpringSecurity
    • Maven
  • PYTHON

    • 概述
    • python3
    • python3(菜鸟教程)
    • pandas
    • numpy
    • matplotlib
  • 中间件

    • Kafka
    • RocketMQ
    • Redis
    • MongoDB
    • Elastic Search
  • 数据库

    • Mysql
  • 前端

    • HTML
    • CSS
    • Javascript
    • Vue2学习笔记
    • Vue3学习笔记
  • 设计模式
  • 大数据

    • 概览
    • Hadoop
    • Hive
  • 机器学习

    • 机器学习概览
  • openclaw实战
  • claudecode实战
  • RAG
  • 拟人类Agent
  • linux命令速查
  • windows命令速查
  • Docker笔记
  • kubernetes学习笔记
  • kubernetes实操笔记
  • 运维工具大全
  • git操作宝典
  • 概率论
  • 线性代数
  • 统计学
  • 金融知识学习
  • 聚宽
  • 因子分析
  • 后端

    • JAVA基础
    • JAVA多线程
    • JVM
    • 分布式相关
    • 数据库
  • 前端

    • HTML
    • CSS
    • JAVASCRIPT
    • VUE3
    • 网络
    • 前端工程化
    • nodejs
  • AI

    • RAG
  • 健身

    • 笔记
    • 训练计划
  • 读书笔记

    • 《深度学习》
  • 其他

    • RSS
    • 资源导航
    • 医保
    • 装修攻略
我也想搭建这样的博客!
🚋开往
  • VUE2

    • 概述
    • Vue2 学习笔记
    • VueRouter
    • Vuex
    • Webpack

Vuex 使用教程

Vuex 是 Vue2 官方的状态管理库,用于管理多个组件共享的状态。Vue3 推荐使用 Pinia 替代。

安装

npm install vuex@3   # Vue2 对应 Vuex 3

核心概念

概念说明类比
state全局响应式状态数据数据库
getters从 state 派生的计算值computed
mutations同步修改 state 的唯一途径setter
actions可包含异步操作,提交 mutationsservice 层
modules将 store 拆分为模块分表

数据流向:

组件 → dispatch(action) → commit(mutation) → 修改 state → 组件响应式更新
组件 → commit(mutation) → 修改 state(简单同步场景可跳过 action)

基础配置

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  // 开启严格模式:state 只能通过 mutation 修改(生产环境关闭,影响性能)
  strict: process.env.NODE_ENV !== 'production',

  state: {
    count: 0,
    userInfo: null,
    token: localStorage.getItem('token') || '',
  },

  getters: {
    // 类似 computed,有缓存
    isLoggedIn: state => !!state.token,
    doubleCount: state => state.count * 2,
    // 接收其他 getter
    countInfo: (state, getters) => `count: ${state.count}, double: ${getters.doubleCount}`,
  },

  mutations: {
    // mutation 必须是同步函数
    INCREMENT(state, payload) {
      state.count += payload || 1
    },
    SET_USER(state, user) {
      state.userInfo = user
    },
    SET_TOKEN(state, token) {
      state.token = token
      localStorage.setItem('token', token)  // 同步到本地存储
    },
    CLEAR_AUTH(state) {
      state.token = ''
      state.userInfo = null
      localStorage.removeItem('token')
    },
  },

  actions: {
    // action 可以是异步的,通过 commit 提交 mutation
    async login({ commit }, credentials) {
      const res = await api.login(credentials)
      commit('SET_TOKEN', res.data.token)
      commit('SET_USER', res.data.user)
      return res.data
    },
    async fetchUserInfo({ commit, state }) {
      if (!state.token) return
      const res = await api.getUserInfo()
      commit('SET_USER', res.data)
    },
    logout({ commit }) {
      commit('CLEAR_AUTH')
    },
  },
})

export default store
// main.js 注册 store
new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

在组件中使用

直接访问

export default {
  computed: {
    count() { return this.$store.state.count },
    isLoggedIn() { return this.$store.getters.isLoggedIn },
  },
  methods: {
    increment() {
      // 提交 mutation(同步)
      this.$store.commit('INCREMENT', 5)
    },
    async login() {
      // 派发 action(异步)
      await this.$store.dispatch('login', { username: 'Tom', password: '123' })
    }
  }
}

辅助函数(推荐)

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {
  computed: {
    // 映射 state
    ...mapState(['count', 'userInfo', 'token']),
    // 重命名
    ...mapState({ myCount: 'count', user: 'userInfo' }),
    // 映射 getters
    ...mapGetters(['isLoggedIn', 'doubleCount']),
  },
  methods: {
    // 映射 mutations
    ...mapMutations(['INCREMENT', 'SET_TOKEN']),
    // 映射 actions
    ...mapActions(['login', 'logout', 'fetchUserInfo']),

    async handleLogin() {
      await this.login({ username: 'Tom', password: '123' })
      this.$router.push('/dashboard')
    }
  }
}

模块化(modules)

项目变大后将 store 拆分为模块:

// src/store/modules/user.js
export default {
  namespaced: true,  // 开启命名空间,避免命名冲突

  state: () => ({
    userInfo: null,
    token: '',
  }),

  getters: {
    isLoggedIn: state => !!state.token,
  },

  mutations: {
    SET_TOKEN(state, token) { state.token = token },
    SET_USER(state, user) { state.userInfo = user },
  },

  actions: {
    async login({ commit }, credentials) {
      const res = await api.login(credentials)
      commit('SET_TOKEN', res.data.token)
      commit('SET_USER', res.data.user)
    }
  }
}
// src/store/modules/cart.js
export default {
  namespaced: true,
  state: () => ({ items: [] }),
  mutations: {
    ADD_ITEM(state, item) { state.items.push(item) },
    REMOVE_ITEM(state, id) {
      state.items = state.items.filter(i => i.id !== id)
    },
  },
  getters: {
    totalCount: state => state.items.length,
    totalPrice: state => state.items.reduce((sum, i) => sum + i.price, 0),
  },
}
// src/store/index.js
import user from './modules/user'
import cart from './modules/cart'

const store = new Vuex.Store({
  modules: { user, cart }
})
// 组件中访问命名空间模块
export default {
  computed: {
    // 方式一:直接访问
    token() { return this.$store.state.user.token },
    isLoggedIn() { return this.$store.getters['user/isLoggedIn'] },
    totalCount() { return this.$store.getters['cart/totalCount'] },

    // 方式二:mapState 指定命名空间
    ...mapState('user', ['userInfo', 'token']),
    ...mapGetters('user', ['isLoggedIn']),
    ...mapGetters('cart', ['totalCount', 'totalPrice']),
  },
  methods: {
    ...mapActions('user', ['login', 'logout']),
    ...mapMutations('cart', ['ADD_ITEM', 'REMOVE_ITEM']),
  }
}

实际项目结构

src/store/
├── index.js          # 入口,组合所有模块
└── modules/
    ├── user.js       # 用户认证、信息
    ├── app.js        # 应用全局配置(主题、语言、侧边栏状态)
    ├── permission.js # 权限、动态路由
    └── cart.js       # 购物车(电商项目)

持久化(vuex-persistedstate)

npm install vuex-persistedstate
import createPersistedState from 'vuex-persistedstate'

const store = new Vuex.Store({
  plugins: [
    createPersistedState({
      key: 'vuex',
      storage: localStorage,
      paths: ['user.token', 'user.userInfo'],  // 只持久化指定字段
    })
  ],
  modules: { user, cart }
})

Vuex 与 Pinia 对比

Vuex 3/4Pinia
mutations必须通过 mutation 修改 state直接修改,无 mutation
模块化需要 namespaced: true 配置每个 store 天然独立
TypeScript有限支持,类型推导较弱完整类型推导
DevTools支持支持
体积较大~1KB
适用版本Vue2(Vuex 3)/ Vue3(Vuex 4)Vue2 / Vue3
Last Updated: 6/25/26, 9:43 AM
Contributors: dongyz8
Prev
VueRouter
Next
Webpack