Module基础 #

为什么需要 Module? #

随着应用复杂度增加,store 对象会变得臃肿。Vuex 允许我们将 store 分割成模块,每个模块拥有自己的 state、mutation、action、getter,甚至是嵌套子模块。

定义模块 #

基本结构 #

javascript
const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

// 访问模块状态
store.state.a  // moduleA 的状态
store.state.b  // moduleB 的状态

完整示例 #

javascript
// 模块定义
const userModule = {
  state: () => ({
    profile: null,
    token: null
  }),
  
  mutations: {
    SET_PROFILE(state, profile) {
      state.profile = profile
    },
    SET_TOKEN(state, token) {
      state.token = token
    }
  },
  
  actions: {
    async fetchProfile({ commit }) {
      const profile = await api.fetchProfile()
      commit('SET_PROFILE', profile)
    }
  },
  
  getters: {
    isLoggedIn: state => !!state.token,
    userName: state => state.profile?.name || 'Guest'
  }
}

const cartModule = {
  state: () => ({
    items: []
  }),
  
  mutations: {
    ADD_ITEM(state, item) {
      state.items.push(item)
    },
    CLEAR_CART(state) {
      state.items = []
    }
  },
  
  getters: {
    itemCount: state => state.items.length,
    total: state => state.items.reduce((sum, item) => sum + item.price, 0)
  }
}

// 组合模块
const store = createStore({
  modules: {
    user: userModule,
    cart: cartModule
  }
})

模块的局部状态 #

State #

模块内的 state 是局部的,只能通过 store.state.moduleName 访问:

javascript
// 访问 user 模块的状态
this.$store.state.user.profile
this.$store.state.user.token

// 访问 cart 模块的状态
this.$store.state.cart.items

Mutation 和 Action #

模块内的 mutation 和 action 注册在全局命名空间:

javascript
// 调用 mutation
this.$store.commit('SET_PROFILE', profile)  // 全局调用

// 分发 action
this.$store.dispatch('fetchProfile')  // 全局调用

Getter #

模块内的 getter 也注册在全局:

javascript
// 访问 getter
this.$store.getters.isLoggedIn
this.$store.getters.itemCount

模块文件组织 #

推荐结构 #

text
store/
├── index.js          # 入口文件,组装模块
├── mutation-types.js # Mutation 常量
└── modules/
    ├── user.js       # 用户模块
    ├── cart.js       # 购物车模块
    └── products.js   # 产品模块

模块文件示例 #

javascript
// store/modules/user.js
import * as types from '../mutation-types'

const state = () => ({
  profile: null,
  token: null,
  loading: false,
  error: null
})

const mutations = {
  [types.SET_PROFILE](state, profile) {
    state.profile = profile
  },
  
  [types.SET_TOKEN](state, token) {
    state.token = token
  },
  
  [types.SET_LOADING](state, loading) {
    state.loading = loading
  },
  
  [types.SET_ERROR](state, error) {
    state.error = error
  }
}

const actions = {
  async login({ commit }, credentials) {
    commit(types.SET_LOADING, true)
    
    try {
      const { user, token } = await api.login(credentials)
      commit(types.SET_PROFILE, user)
      commit(types.SET_TOKEN, token)
      return user
    } catch (error) {
      commit(types.SET_ERROR, error.message)
      throw error
    } finally {
      commit(types.SET_LOADING, false)
    }
  },
  
  logout({ commit }) {
    commit(types.SET_PROFILE, null)
    commit(types.SET_TOKEN, null)
  }
}

const getters = {
  isLoggedIn: state => !!state.token,
  userName: state => state.profile?.name || 'Guest',
  userEmail: state => state.profile?.email || ''
}

export default {
  namespaced: true,  // 推荐开启命名空间
  state,
  mutations,
  actions,
  getters
}

入口文件 #

javascript
// store/index.js
import { createStore } from 'vuex'
import user from './modules/user'
import cart from './modules/cart'
import products from './modules/products'

export default createStore({
  modules: {
    user,
    cart,
    products
  },
  
  // 全局状态(可选)
  state: {
    appLoading: false,
    appError: null
  }
})

嵌套模块 #

定义嵌套模块 #

javascript
const store = createStore({
  modules: {
    account: {
      namespaced: true,
      
      state: () => ({ ... }),
      mutations: { ... },
      actions: { ... },
      getters: { ... },
      
      modules: {
        // 嵌套模块
        posts: {
          namespaced: true,
          state: () => ({ ... }),
          mutations: { ... }
        },
        comments: {
          namespaced: true,
          state: () => ({ ... }),
          mutations: { ... }
        }
      }
    }
  }
})

// 访问嵌套模块状态
store.state.account.posts
store.state.account.comments

模块重用 #

创建可重用模块 #

javascript
function createCounterModule(initialValue = 0) {
  return {
    namespaced: true,
    
    state: () => ({
      count: initialValue
    }),
    
    mutations: {
      INCREMENT(state) {
        state.count++
      },
      DECREMENT(state) {
        state.count--
      },
      SET_COUNT(state, value) {
        state.count = value
      }
    },
    
    actions: {
      increment({ commit }) {
        commit('INCREMENT')
      },
      decrement({ commit }) {
        commit('DECREMENT')
      }
    },
    
    getters: {
      doubleCount: state => state.count * 2
    }
  }
}

// 使用可重用模块
const store = createStore({
  modules: {
    counterA: createCounterModule(10),
    counterB: createCounterModule(20)
  }
})

模块注册 #

静态注册 #

javascript
// 创建 store 时注册
const store = createStore({
  modules: {
    user: userModule,
    cart: cartModule
  }
})

动态注册 #

javascript
// 创建 store 后注册
store.registerModule('products', {
  state: () => ({ items: [] }),
  mutations: {
    SET_ITEMS(state, items) {
      state.items = items
    }
  }
})

// 访问动态注册的模块
store.state.products

// 卸载模块
store.unregisterModule('products')

最佳实践 #

1. 开启命名空间 #

javascript
export default {
  namespaced: true,  // 推荐
  state,
  mutations,
  actions,
  getters
}

2. 按功能划分模块 #

javascript
modules: {
  user,       // 用户相关
  cart,       // 购物车相关
  products,   // 产品相关
  orders,     // 订单相关
  ui          // UI 状态
}

3. 保持模块独立 #

javascript
// 推荐:模块独立,通过 action 通信
// user 模块
actions: {
  async login({ dispatch }) {
    // 登录成功后获取购物车
    await dispatch('cart/fetchCart', null, { root: true })
  }
}

// 不推荐:直接访问其他模块状态
actions: {
  login({ rootState }) {
    const cart = rootState.cart  // 耦合度高
  }
}

总结 #

Module 核心要点:

要点 说明
模块定义 独立的 state、mutations、actions、getters
局部状态 模块 state 是局部的
全局注册 默认 mutations/actions/getters 是全局的
命名空间 推荐开启 namespaced
文件组织 按功能模块拆分文件

继续学习 模块局部状态,深入了解模块内部状态管理。

最后更新:2026-03-28