项目结构 #

推荐目录结构 #

标准结构 #

text
src/
├── store/
│   ├── index.js              # 入口文件,组装模块并导出 store
│   ├── mutation-types.js     # Mutation 常量
│   ├── actions.js            # 根级别的 action(可选)
│   ├── mutations.js          # 根级别的 mutation(可选)
│   ├── getters.js            # 根级别的 getter(可选)
│   └── modules/              # 模块目录
│       ├── user.js           # 用户模块
│       ├── cart.js           # 购物车模块
│       ├── products.js       # 产品模块
│       └── ui.js             # UI 状态模块
├── composables/              # 组合式函数
│   ├── useUserStore.js
│   ├── useCartStore.js
│   └── useProductStore.js
└── main.js

大型项目结构 #

text
src/
├── store/
│   ├── index.js
│   ├── mutation-types.js
│   ├── modules/
│   │   ├── user/
│   │   │   ├── index.js      # 模块入口
│   │   │   ├── state.js      # 状态
│   │   │   ├── mutations.js  # 变更
│   │   │   ├── actions.js    # 动作
│   │   │   └── getters.js    # 派生状态
│   │   ├── cart/
│   │   │   ├── index.js
│   │   │   ├── state.js
│   │   │   ├── mutations.js
│   │   │   ├── actions.js
│   │   │   └── getters.js
│   │   └── products/
│   │       └── ...
│   └── plugins/
│       ├── persistence.js    # 持久化插件
│       └── logger.js         # 日志插件
└── composables/
    └── ...

入口文件 #

基本入口 #

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
  },
  
  strict: process.env.NODE_ENV !== 'production'
})

完整入口 #

javascript
// store/index.js
import { createStore } from 'vuex'
import * as types from './mutation-types'

// 模块
import user from './modules/user'
import cart from './modules/cart'
import products from './modules/products'
import ui from './modules/ui'

// 插件
import createPersistence from './plugins/persistence'

const debug = process.env.NODE_ENV !== 'production'

const store = createStore({
  modules: {
    user,
    cart,
    products,
    ui
  },
  
  // 根状态
  state: {
    appVersion: '1.0.0',
    appReady: false
  },
  
  // 根 mutation
  mutations: {
    [types.SET_APP_READY](state, ready) {
      state.appReady = ready
    }
  },
  
  // 根 action
  actions: {
    async initApp({ dispatch, commit }) {
      await Promise.all([
        dispatch('user/checkAuth'),
        dispatch('products/fetchCategories')
      ])
      
      commit(types.SET_APP_READY, true)
    }
  },
  
  // 根 getter
  getters: {
    appVersion: state => state.appVersion,
    isAppReady: state => state.appReady
  },
  
  // 插件
  plugins: debug 
    ? [createLogger()] 
    : [createPersistence()],
  
  // 严格模式
  strict: debug
})

export default store

模块文件 #

单文件模块 #

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_USER_PROFILE](state, profile) {
    state.profile = profile
  },
  
  [types.SET_USER_TOKEN](state, token) {
    state.token = token
  },
  
  [types.SET_USER_LOADING](state, loading) {
    state.loading = loading
  },
  
  [types.SET_USER_ERROR](state, error) {
    state.error = error
  }
}

const actions = {
  async login({ commit }, credentials) {
    commit(types.SET_USER_LOADING, true)
    commit(types.SET_USER_ERROR, null)
    
    try {
      const { user, token } = await api.login(credentials)
      commit(types.SET_USER_PROFILE, user)
      commit(types.SET_USER_TOKEN, token)
      return user
    } catch (error) {
      commit(types.SET_USER_ERROR, error.message)
      throw error
    } finally {
      commit(types.SET_USER_LOADING, false)
    }
  },
  
  logout({ commit }) {
    commit(types.SET_USER_PROFILE, null)
    commit(types.SET_USER_TOKEN, null)
  }
}

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

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

多文件模块 #

javascript
// store/modules/user/index.js
import state from './state'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}
javascript
// store/modules/user/state.js
export default () => ({
  profile: null,
  token: null,
  loading: false,
  error: null
})
javascript
// store/modules/user/mutations.js
import * as types from '../../mutation-types'

export default {
  [types.SET_USER_PROFILE](state, profile) {
    state.profile = profile
  },
  
  [types.SET_USER_TOKEN](state, token) {
    state.token = token
  }
}

Mutation 类型文件 #

javascript
// store/mutation-types.js

// User
export const SET_USER_PROFILE = 'SET_USER_PROFILE'
export const SET_USER_TOKEN = 'SET_USER_TOKEN'
export const SET_USER_LOADING = 'SET_USER_LOADING'
export const SET_USER_ERROR = 'SET_USER_ERROR'

// Cart
export const ADD_CART_ITEM = 'ADD_CART_ITEM'
export const REMOVE_CART_ITEM = 'REMOVE_CART_ITEM'
export const UPDATE_CART_QUANTITY = 'UPDATE_CART_QUANTITY'
export const CLEAR_CART = 'CLEAR_CART'

// Products
export const SET_PRODUCTS = 'SET_PRODUCTS'
export const SET_CATEGORIES = 'SET_CATEGORIES'
export const SET_CURRENT_PRODUCT = 'SET_CURRENT_PRODUCT'

// UI
export const SET_LOADING = 'SET_LOADING'
export const SET_ERROR = 'SET_ERROR'
export const SET_TOAST = 'SET_TOAST'

模块命名规范 #

按功能命名 #

text
modules/
├── auth.js          # 认证
├── user.js          # 用户
├── cart.js          # 购物车
├── products.js      # 产品
├── orders.js        # 订单
├── notifications.js # 通知
└── ui.js            # UI 状态

按领域命名 #

text
modules/
├── account/         # 账户领域
│   ├── profile.js
│   └── settings.js
├── commerce/        # 商业领域
│   ├── cart.js
│   ├── products.js
│   └── orders.js
└── system/          # 系统领域
    ├── notifications.js
    └── ui.js

状态结构设计 #

扁平化设计 #

javascript
// 推荐:扁平化
state: {
  users: {
    byId: {
      1: { id: 1, name: 'John' },
      2: { id: 2, name: 'Jane' }
    },
    allIds: [1, 2]
  }
}

// 不推荐:深层嵌套
state: {
  data: {
    users: {
      list: {
        items: []
      }
    }
  }
}

分离业务数据和 UI 状态 #

javascript
// 业务数据
state: {
  entities: {
    users: {},
    products: {},
    orders: {}
  }
}

// UI 状态
state: {
  ui: {
    loading: false,
    error: null,
    selectedId: null,
    filters: {}
  }
}

最佳实践 #

1. 模块独立 #

javascript
// 每个模块应该是独立的
export default {
  namespaced: true,  // 开启命名空间
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

2. 统一导出 #

javascript
// store/modules/index.js
export { default as user } from './user'
export { default as cart } from './cart'
export { default as products } from './products'

// store/index.js
import * as modules from './modules'

export default createStore({
  modules
})

3. 类型安全 #

typescript
// 使用 TypeScript 提供类型支持
interface UserState {
  profile: User | null
  token: string | null
}

const state: () => UserState = () => ({
  profile: null,
  token: null
})

总结 #

项目结构要点:

要点 说明
模块化 按功能分割模块
命名空间 开启 namespaced
常量命名 使用 mutation-types.js
扁平化 避免深层嵌套
分离关注点 业务数据与 UI 状态分离

继续学习 Vuex与TypeScript,了解 TypeScript 集成。

最后更新:2026-03-28