map 辅助函数是 Vuex 提供的一种方便的方式,用于将 Vuex 中的状态、getters、mutations 和 actions 映射到 Vue 组件中的本地状态、计算属性、方法和动作。
map 辅助函数 使用方法 mapState(namespace?: string, map: Array<string> | Object<string | function>): Object 这里以 mapState 为例,简单看下 map 辅助函数的三种使用方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 export default { computed : mapState ({ count : state => state.count , countAlias : 'count' , countPlusLocalState (state) { return state.count + this .localCount } }) }
如果不考虑 namespace,以数组为例,可以很简单的实现实现 mapState 方法:
1 2 3 4 5 6 7 8 9 const mapState = args => { let states = {} args.forEach (item => { states[item] = function ( ) { return this .$store .state [item] } }) return states }
normalizeMap 由于用户传入可能为数组或对象,首先需要格式化参数格式
1 2 3 4 5 function normalizeMap (map ) { return Array .isArray (map) ? map.map (key => ({ key, val : key })) : Object .keys (map).map (key => ({ key, val : map[key] })) }
normalizeNamespace 根据 namespace 配置,对开启命名空间的模块,拼接路径参数
1 2 3 4 5 6 7 8 9 10 11 function normalizeNamespace (fn ) { return (namespace, map ) => { if (typeof namespace !== 'string' ) { map = namespace namespace = '' } else if (namespace.charAt (namespace.length - 1 ) !== '/' ) { namespace += '/' } return fn (namespace, map) } }
getModuleByNamespace 获取 namespace 对应的 module 模块,注:这里可以参考 namespace 一节中的数据结构,就很容易理解
1 2 3 4 5 6 7 function getModuleByNamespace (store, helper, namespace ) { const module = store._modulesNamespaceMap [namespace] if (!module ) { console .error (`[vuex] module namespace not found in ${helper} (): ${namespace} ` ) } return module }
mapState 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 export const mapState = normalizeNamespace ((namespace, states ) => { const res = {} normalizeMap (states).forEach (({ key, val } ) => { res[key] = function mappedState ( ) { let state = this .$store .state let getters = this .$store .getters if (namespace) { const module = getModuleByNamespace (this .$store , 'mapState' , namespace) if (!module ) { return } state = module .state getters = module .getters } return typeof val === 'function' ? val.call (this , state, getters) : state[val] } }) return res })
同理可依次实现 mapGetters、mapMutations、mapActions 辅助函数
mapGetters 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 export const mapGetters = normalizeNamespace ((namespace, getters ) => { const res = {} normalizeMap (getters).forEach (({ key, val } ) => { val = namespace + val res[key] = function mappedGetter ( ) { if (namespace && !getModuleByNamespace (this .$store , 'mapGetters' , namespace)) { return } return this .$store .getters [val] } }) return res })
mapMutations 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 export const mapMutations = normalizeNamespace ((namespace, mutations ) => { const res = {} normalizeMap (mutations).forEach (({ key, val } ) => { res[key] = function mappedMutation (...args ) { let commit = this .$store .commit if (namespace) { const module = getModuleByNamespace (this .$store , 'mapMutations' , namespace) if (!module ) { return } const _type = namespace + val commit = () => { this .$store .commit (_type) } } return typeof val === 'function' ? val.apply (this , [commit].concat (args)) : commit.apply (this .$store , [val].concat (args)) } }) return res })
mapActions 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 export const mapActions = normalizeNamespace ((namespace, actions ) => { const res = {} normalizeMap (actions).forEach (({ key, val } ) => { res[key] = function mappedAction (...args ) { let dispatch = this .$store .dispatch if (namespace) { const module = getModuleByNamespace (this .$store , 'mapActions' , namespace) if (!module ) { return } const _type = namespace + val dispatch = () => { return this .$store .dispatch (_type) } } return typeof val === 'function' ? val.apply (this , [dispatch].concat (args)) : dispatch.apply (this .$store , [val].concat (args)) } }) return res })
至此,手写 Vuex 基础功能、模块化、命名空间、严格模式等已完结,以源码为例,实现了一个简易的Vuex3,帮助我们理解其原理,希望这篇文章对你有所帮助!更多详细信息请参考 vuex 源码 。
系列文章