Skip to content

helpers

mapState

javascript
computed: {
  // 将 this.foo 映射为 this.$store.state.foo
  // 将 this.bar 映射为 this.$store.state.bar
  ...mapState(['foo', 'bar'])
  // 将 this.foo 映射为 this.state.a.foo
  ...mapState('a',['foo'])
  // 将 this.foo 映射为 this.state.a.foo
  ...mapState('a/',['foo'])
  // 将 this.myFoo 映射为 this.state.a.foo
  ...mapState('a', { myFoo: 'foo' }) 
  ...mapState({ 
    // 将 this.foo 映射为函数执行的结果
    foo: state => state.count, 
    // 将 this.foo 映射为函数执行的结果
    bar (state) {
      return state.bar + this.baz
    }
  })
}
javascript
function normalizeNamespace (fn) {
  return (namespace, map) => {
    // mapState(namespace, ['foo‘])
    if (typeof namespace !== 'string') {
      // 没传 namespace
      map = namespace
      namespace = ''
    } else if (namespace.charAt(namespace.length - 1) !== '/') {
      // 补充 /
      namespace += '/'
    }
    return fn(namespace, map)
  }
}

function normalizeMap (map) {
  if (!isValidMap(map)) {
    return []
  }
  // 标准化为对象形式,然后在 computed 中展开,就可以通过 computed 快速访问。
  return Array.isArray(map)
    ? map.map(key => ({ key, val: key }))
    : Object.keys(map).map(key => ({ key, val: map[key] }))
}

function isValidMap (map) {
  return Array.isArray(map) || isObject(map)
}

function installModule (store, rootState, path, module) {
  if (module.namespaced) {
    if (store._modulesNamespaceMap[namespace] && __DEV__) {
      console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}`)
    }
    store._modulesNamespaceMap[namespace] = module
  }
}

function getModuleByNamespace (store, helper, namespace) {
  const module = store._modulesNamespaceMap[namespace]
  if (__DEV__ && !module) {
    console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`)
  }
  return module
}

const mapState = normalizeNamespace((namespace, states) => {
  // mapState(['foo', 'bar'])
  // =>
  // {
  //   foo () {
  //     return this.$store.state.foo
  //   },
  //   bar () {
  //     return this.$store.state.bar
  //   }
  // }

  // mapState({ myFoo: foo, 'bar' })
  // =>
  // {
  //   myFoo () {
  //     return this.$store.state.foo
  //   },
  //   bar () {
  //     return this.$store.state.bar
  //   }
  // }

  // mapState({ 
  //   foo: state => state.foo,
  //   bar (state) {
  //     return state.bar + this.baz
  //   }
  // })
  // =>
  // {
  //   foo () {
  //     return cb.call(this, state, getters)
  //   },
  //   bar () {
  //     return cb.call(this, state, getters)
  //   }
  // }
  const res = {}
  if (__DEV__ && !isValidMap(states)) {
    console.error('[vuex] mapState: mapper parameter must be either an Array or an Object')
  }
  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.context.state
        getters = module.context.getters
      }
      return typeof val === 'function'
        ? val.call(this, state, getters)
        : state[val]
    }
  })
  return res
})

mapMutations

javascript
methods: {
  ...mapMutations([
    // 将 this.foo() 映射为 this.$store.commit('foo'),调用时支持 payload
    // 将 this.foo(payload) 映射为 this.$store.commit('foo', payload)
    'foo', 
    // 将 this.bar() 映射为 this.$store.commit('bar')
    'bar'
  ]),
  ...mapMutations({
    // 将 this.baz() 映射为 this.$store.commit('baz')
    baz: 'foo' 
  })
}
javascript
const mapMutations = normalizeNamespace((namespace, mutations) => {
  const res = {}
  if (__DEV__ && !isValidMap(mutations)) {
    console.error('[vuex] mapMutations: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(mutations).forEach(({ key, val }) => {
    res[key] = function mappedMutation (...args) {
      // Get the commit method from store
      let commit = this.$store.commit
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapMutations', namespace)
        if (!module) {
          return
        }
        commit = module.context.commit
      }
      return typeof val === 'function'
        ? val.apply(this, [commit].concat(args))
        : commit.apply(this.$store, [val].concat(args))
    }
  })
  return res
})

mapGetters

javascript
const mapGetters = normalizeNamespace((namespace, getters) => {
  const res = {}
  if (__DEV__ && !isValidMap(getters)) {
    console.error('[vuex] mapGetters: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(getters).forEach(({ key, val }) => {
    // The namespace has been mutated by normalizeNamespace
    val = namespace + val
    res[key] = function mappedGetter () {
      if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {
        return
      }
      if (__DEV__ && !(val in this.$store.getters)) {
        console.error(`[vuex] unknown getter: ${val}`)
        return
      }
      return this.$store.getters[val]
    }
  })
  return res
})