一篇文章带你彻底搞懂vuex命名空间

文章发布于 2023-07-09

命名空间

命名空间的作用是为了减少模块之间定义的方法命名冲突的问题。默认state是局部命名空间 ,mutation、action、getter 是全局命名空间。比如说在a模块getter 中定义一个getter1,在b模块getter 中也定义一个getter1 ,在同一空间内,拥有两个相同的名称,程序会报错。

局部命名空间

在模块内定义namespaced:true 。模块所有的mutation、action、getter 则都是局部

const store = Vuex.Stroe({
    modules:{
        a:{
            namespaced:true,
            state:{
                username:''
            },  // a.state
            mutations:{
                login(state,payload){
                    state.username= payload.username
                }
            },
            actions:{
                login(connext ,payload){
                    connext.commit('login',payload)  //dispatch('a/login')
                }
            } 
        }
    }
})

嵌套命名空间

子模块默认使用父模块的命名空间。设置namespaced:true 则拥有自己的命名空间。

const store = Vuex.Store({
    modules:{
        a:{
            namespaced:true,
            state:{},
            actions:{},
            modules:{
                one_module:{
                    state:{},
                    mutations:{
                        one(){}  // 'a/one'
                    }
                },
                two_module:{
                    namespaced:true,
                    state:{},
                    mutations:{
                        qt(){}  // 'a/two_module/qt'
                    }
                }
            }
        }
    }
})

局部命名空间访问全局内容

如果想在命名空间内,使用全局的state、getter 。提供rootStaterootGetters

modules:{
    foo:{
        namespaced:true,
        getters:{
            some(state, getters, rootState, rootGetters){
                rootState.username // 全局state
                rootGetters.getter1 // 全局getter1
                getters.getter1 //foo/getter1
            },
            getter1(){}
        }
    }
}

局部命名空间访问全局dispatch 和commit

使用root:true ,让局部化的dispatch 和commit 访问根dispatch 和commit

commit('someMutation', null, { root: true }) 
dispatch('someOtherAction', null, { root: true }) 

局部命名空间注册全局action

在带命名空间的模块注册全局 action,可以添加 root: true,并将这个 action 的定义放在函数 handler 中。

actions: {
     action1: {
          root: true,
          handler (namespacedContext, payload) {  }
     }
}

局部命名空间的辅助函数

使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。

const { mapState, mapActions } = createNamespacedHelpers('a')

computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
}

带命名空间的分发action ,a是注册模块名

// 载荷方式
this.$store.dispatch('a/login',{
    username:'admin'
})


//对象方式
this.$store.dispatch({
    type:'a/login',
    username:'admin'
})

//直接分发
this.$store.dispatch('a/incrment')

实例

实现一个简单易上手的实例:

1 创建一个store 仓库 ,并且注册两个模块(一个全局,一个局部)。store.js

// vuex version 4.x
import {createStore } from 'vuex'
// 全局
import modelA from './modelA.js'
//局部
import modelB from './modelB.js'

const store = createStore({
    modules:{
        a:modelA,
        b:modelB
    }
})

export default store

2 创建一个不带命名空间的模块。modelA.js

const modelA = {
    state:{
        website_name:'编程领地'
    },
    mutations:{
        setWebsite_name(state ,payload){
            state.website_name = payload.website_name
        },
        getter_g1:state=>state.website_name
    }
}

export default modelA

3 创建一个带命名空间的模块。modelB.js

const modelB = {
    namespaced:true,
    state:{
        website_url:'https://www.itboolean.com'
    },
    mutations:{
        setWebsite_Url(state ,payload){
            state.website_url = payload.website_url
        },
        getter1(state,getters ,rootState ,rootGetters){
            console.log(state.website_url) //https://

            console.log(state,getters ,rootState ,rootGetters)
        }
    }
}

export default modelB

4 创建一个vue文件,然后分别调用。app.vue

<script setup>
import {computed} from 'vue'
import { useStore ,createNamespacedHelpers } from 'vuex'
const store = useStore()

// 不带命名空间的mutations 使用的全局空间。
store.commit('setWebsite_name' ,{
    website_name : '编程领地 good'
})

//访问带命名空间的局部mutations ,带上注册的模块名
store.commit('b/setWebsite_Url',{
    website_url:'https://'
})

//调用局部命名空间的getter
store.commit('b/getter1')

//vue 组合式setup 中 使用辅助函数 获取state
const {mapState} = createNamespacedHelpers('b')

const storeStateFns = mapState(['website_url'])
const storeState = {}
Object.keys(storeStateFns).forEach(item => {
    const fn = storeStateFns[item].bind({$store: store})
    //每个执行一次computed
    storeState[item] = computed(fn)
})

</script>

<template>
    <div>
        <div>
            标题:{{store.state.a.website_name}}
        </div>
        <div>
            链接:{{store.state.b.website_url}}
        </div>
        {{storeState.website_url}}
    </div>

</template>