命名空间 #

什么是命名空间? #

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的。开启命名空间后,模块会更有封装性和复用性。

开启命名空间 #

基本用法 #

javascript
const moduleA = {
  namespaced: true,  // 开启命名空间
  
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

命名空间效果 #

javascript
const store = createStore({
  modules: {
    user: {
      namespaced: true,
      
      state: () => ({ name: 'John' }),
      
      mutations: {
        SET_NAME(state, name) {
          state.name = name
        }
      },
      
      actions: {
        fetchUser({ commit }) {
          // ...
        }
      },
      
      getters: {
        userName: state => state.name
      }
    }
  }
})

// 访问方式改变
store.state.user.name           // state 不变
store.commit('user/SET_NAME')   // mutation 需要加前缀
store.dispatch('user/fetchUser') // action 需要加前缀
store.getters['user/userName']  // getter 需要加前缀

在组件中使用 #

直接访问 #

javascript
// State
this.$store.state.user.name

// Mutation
this.$store.commit('user/SET_NAME', 'Jane')

// Action
this.$store.dispatch('user/fetchUser')

// Getter
this.$store.getters['user/userName']

使用辅助函数 #

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

export default {
  computed: {
    // 指定模块命名空间
    ...mapState('user', ['name']),
    ...mapGetters('user', ['userName'])
  },
  
  methods: {
    ...mapMutations('user', ['SET_NAME']),
    ...mapActions('user', ['fetchUser'])
  }
}

使用 createNamespacedHelpers #

javascript
import { createNamespacedHelpers } from 'vuex'

// 创建基于某个命名空间的辅助函数
const { mapState, mapGetters, mapMutations, mapActions } = 
  createNamespacedHelpers('user')

export default {
  computed: {
    // 无需再指定命名空间
    ...mapState(['name']),
    ...mapGetters(['userName'])
  },
  
  methods: {
    ...mapMutations(['SET_NAME']),
    ...mapActions(['fetchUser'])
  }
}

在模块内访问全局内容 #

访问全局 Action #

javascript
const moduleA = {
  namespaced: true,
  
  actions: {
    // 局部 action
    someAction({ commit, dispatch }) {
      // 调用局部 mutation
      commit('SET_DATA', data)
      
      // 调用全局 action
      dispatch('globalAction', null, { root: true })
      
      // 调用其他模块的 action
      dispatch('user/login', credentials, { root: true })
    }
  }
}

访问全局 Mutation #

javascript
actions: {
  someAction({ commit }) {
    // 调用局部 mutation
    commit('SET_LOCAL_DATA', data)
    
    // 调用全局 mutation
    commit('SET_GLOBAL_DATA', data, { root: true })
    
    // 调用其他模块的 mutation
    commit('user/SET_NAME', name, { root: true })
  }
}

注册全局 Action #

javascript
const moduleA = {
  namespaced: true,
  
  actions: {
    // 局部 action
    localAction({ commit }) {
      // ...
    },
    
    // 注册全局 action
    globalAction: {
      root: true,  // 注册到全局
      handler({ commit }) {
        // ...
      }
    }
  }
}

// 调用
this.$store.dispatch('globalAction')  // 不需要命名空间前缀

注册全局 Mutation #

javascript
const moduleA = {
  namespaced: true,
  
  mutations: {
    // 局部 mutation
    SET_LOCAL_DATA(state, data) {
      // ...
    }
  }
}

// 如果需要全局 mutation,在模块外定义
const store = createStore({
  modules: {
    moduleA
  },
  
  mutations: {
    SET_GLOBAL_DATA(state, data) {
      // ...
    }
  }
})

带命名空间的绑定函数 #

简化绑定 #

javascript
import { createNamespacedHelpers } from 'vuex'

const { mapState, mapGetters, mapMutations, mapActions } = 
  createNamespacedHelpers('user')

export default {
  computed: {
    ...mapState({
      name: state => state.name,
      email: state => state.email
    }),
    
    ...mapGetters([
      'isLoggedIn',
      'userName'
    ])
  },
  
  methods: {
    ...mapMutations([
      'SET_NAME',
      'SET_EMAIL'
    ]),
    
    ...mapActions([
      'login',
      'logout'
    ])
  }
}

重命名 #

javascript
const { mapState, mapActions } = createNamespacedHelpers('user')

export default {
  computed: {
    ...mapState({
      currentUserName: 'name',
      currentUserEmail: 'email'
    })
  },
  
  methods: {
    ...mapActions({
      signIn: 'login',
      signOut: 'logout'
    })
  }
}

嵌套模块的命名空间 #

定义嵌套模块 #

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.commit('account/posts/SET_POSTS', posts)
store.dispatch('account/posts/fetchPosts')
store.getters['account/posts/allPosts']

使用辅助函数 #

javascript
import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('account/posts')

export default {
  computed: {
    ...mapState(['items'])
  },
  
  methods: {
    ...mapActions(['fetchPosts'])
  }
}

实战示例 #

用户模块 #

javascript
// store/modules/user.js
export default {
  namespaced: true,
  
  state: () => ({
    profile: null,
    token: null,
    loading: false
  }),
  
  mutations: {
    SET_PROFILE(state, profile) {
      state.profile = profile
    },
    SET_TOKEN(state, token) {
      state.token = token
    },
    SET_LOADING(state, loading) {
      state.loading = loading
    }
  },
  
  actions: {
    async login({ commit }, credentials) {
      commit('SET_LOADING', true)
      
      try {
        const { user, token } = await api.login(credentials)
        commit('SET_PROFILE', user)
        commit('SET_TOKEN', token)
        return user
      } finally {
        commit('SET_LOADING', false)
      }
    },
    
    logout({ commit }) {
      commit('SET_PROFILE', null)
      commit('SET_TOKEN', null)
    }
  },
  
  getters: {
    isLoggedIn: state => !!state.token,
    userName: state => state.profile?.name || 'Guest'
  }
}

组件中使用 #

vue
<template>
  <div>
    <p v-if="isLoggedIn">Welcome, {{ userName }}</p>
    <button @click="login({ username, password })">Login</button>
    <button @click="logout">Logout</button>
  </div>
</template>

<script>
import { createNamespacedHelpers } from 'vuex'

const { mapState, mapGetters, mapActions } = 
  createNamespacedHelpers('user')

export default {
  data() {
    return {
      username: '',
      password: ''
    }
  },
  
  computed: {
    ...mapState(['loading']),
    ...mapGetters(['isLoggedIn', 'userName'])
  },
  
  methods: {
    ...mapActions(['login', 'logout'])
  }
}
</script>

最佳实践 #

1. 始终开启命名空间 #

javascript
// 推荐
export default {
  namespaced: true,
  // ...
}

// 不推荐(除非有特殊需求)
export default {
  namespaced: false,
  // ...
}

2. 使用 createNamespacedHelpers #

javascript
// 推荐:更简洁
const { mapState, mapActions } = createNamespacedHelpers('user')

// 不推荐:重复写命名空间
...mapState('user', ['name'])
...mapActions('user', ['login'])

3. 模块命名清晰 #

javascript
// 推荐:清晰的模块名
modules: {
  user,
  cart,
  products,
  orders
}

// 不推荐:模糊的模块名
modules: {
  module1,
  module2,
  data
}

总结 #

命名空间使用要点:

操作 无命名空间 有命名空间
State state.module state.module
Mutation commit('MUTATION') commit('module/MUTATION')
Action dispatch('action') dispatch('module/action')
Getter getters.getter getters['module/getter']

继续学习 模块注册,了解动态注册模块。

最后更新:2026-03-28