Quellcode durchsuchen

support namespace in helpers

Evan You vor 8 Jahren
Ursprung
Commit
5027b73595
3 geänderte Dateien mit 163 neuen und 15 gelöschten Zeilen
  1. 40 10
      src/helpers.js
  2. 9 5
      src/index.js
  3. 114 0
      test/unit/helpers.spec.js

+ 40 - 10
src/helpers.js

@@ -1,28 +1,41 @@
-export function mapState (states) {
+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 = this.$store._modulesNamespaceMap[namespace]
+        if (!module) {
+          warnNamespace('mapState', namespace)
+          return
+        }
+        state = module.state
+        getters = module.context.getters
+      }
       return typeof val === 'function'
-        ? val.call(this, this.$store.state, this.$store.getters)
-        : this.$store.state[val]
+        ? val.call(this, state, getters)
+        : state[val]
     }
   })
   return res
-}
+})
 
-export function mapMutations (mutations) {
+export const mapMutations = normalizeNamespace((namespace, mutations) => {
   const res = {}
   normalizeMap(mutations).forEach(({ key, val }) => {
+    val = namespace + val
     res[key] = function mappedMutation (...args) {
       return this.$store.commit.apply(this.$store, [val].concat(args))
     }
   })
   return res
-}
+})
 
-export function mapGetters (getters) {
+export const mapGetters = normalizeNamespace((namespace, getters) => {
   const res = {}
   normalizeMap(getters).forEach(({ key, val }) => {
+    val = namespace + val
     res[key] = function mappedGetter () {
       if (!(val in this.$store.getters)) {
         console.error(`[vuex] unknown getter: ${val}`)
@@ -31,20 +44,37 @@ export function mapGetters (getters) {
     }
   })
   return res
-}
+})
 
-export function mapActions (actions) {
+export const mapActions = normalizeNamespace((namespace, actions) => {
   const res = {}
   normalizeMap(actions).forEach(({ key, val }) => {
+    val = namespace + val
     res[key] = function mappedAction (...args) {
       return this.$store.dispatch.apply(this.$store, [val].concat(args))
     }
   })
   return res
-}
+})
 
 function normalizeMap (map) {
   return Array.isArray(map)
     ? map.map(key => ({ key, val: key }))
     : Object.keys(map).map(key => ({ key, val: map[key] }))
 }
+
+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)
+  }
+}
+
+function warnNamespace (helper, namespace) {
+  console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`)
+}

+ 9 - 5
src/index.js

@@ -23,6 +23,7 @@ class Store {
     this._mutations = Object.create(null)
     this._wrappedGetters = Object.create(null)
     this._modules = new ModuleCollection(options)
+    this._modulesNamespaceMap = Object.create(null)
     this._subscribers = []
     this._watcherVM = new Vue()
 
@@ -81,10 +82,7 @@ class Store {
     })
     this._subscribers.forEach(sub => sub(mutation, this.state))
 
-    if (
-      process.env.NODE_ENV !== 'production' &&
-      options && options.hasOwnProperty('silent')
-    ) {
+    if (options && options.silent) {
       console.warn(
         `[vuex] mutation type: ${type}. Silent option has been removed. ` +
         'Use the filter functionality in the vue-devtools'
@@ -170,6 +168,7 @@ function resetStore (store) {
   store._actions = Object.create(null)
   store._mutations = Object.create(null)
   store._wrappedGetters = Object.create(null)
+  store._modulesNamespaceMap = Object.create(null)
   const state = store.state
   // init all modules
   installModule(store, state, [], store._modules.root, true)
@@ -223,6 +222,11 @@ function installModule (store, rootState, path, module, hot) {
   const isRoot = !path.length
   const namespace = store._modules.getNamespace(path)
 
+  // register in namespace map
+  if (namespace) {
+    store._modulesNamespaceMap[namespace] = module
+  }
+
   // set state
   if (!isRoot && !hot) {
     const parentState = getNestedState(rootState, path.slice(0, -1))
@@ -232,7 +236,7 @@ function installModule (store, rootState, path, module, hot) {
     })
   }
 
-  const local = makeLocalContext(store, namespace)
+  const local = module.context = makeLocalContext(store, namespace)
 
   module.forEachMutation((mutation, key) => {
     const namespacedType = namespace + key

+ 114 - 0
test/unit/helpers.spec.js

@@ -39,6 +39,31 @@ describe('Helpers', () => {
     expect(vm.a).toBe(4)
   })
 
+  it('mapState (with namespace)', () => {
+    const store = new Vuex.Store({
+      modules: {
+        foo: {
+          namespaced: true,
+          state: { a: 1 },
+          getters: {
+            b: state => state.a + 1
+          }
+        }
+      }
+    })
+    const vm = new Vue({
+      store,
+      computed: mapState('foo', {
+        a: (state, getters) => {
+          return state.a + getters.b
+        }
+      })
+    })
+    expect(vm.a).toBe(3)
+    store.state.foo.a++
+    expect(vm.a).toBe(5)
+  })
+
   it('mapMutations (array)', () => {
     const store = new Vuex.Store({
       state: { count: 0 },
@@ -78,6 +103,32 @@ describe('Helpers', () => {
     expect(store.state.count).toBe(0)
   })
 
+  it('mapMutations (with namespace)', () => {
+    const store = new Vuex.Store({
+      modules: {
+        foo: {
+          namespaced: true,
+          state: { count: 0 },
+          mutations: {
+            inc: state => state.count++,
+            dec: state => state.count--
+          }
+        }
+      }
+    })
+    const vm = new Vue({
+      store,
+      methods: mapMutations('foo', {
+        plus: 'inc',
+        minus: 'dec'
+      })
+    })
+    vm.plus()
+    expect(store.state.foo.count).toBe(1)
+    vm.minus()
+    expect(store.state.foo.count).toBe(0)
+  })
+
   it('mapGetters (array)', () => {
     const store = new Vuex.Store({
       state: { count: 0 },
@@ -135,6 +186,41 @@ describe('Helpers', () => {
     expect(vm.b).toBe(true)
   })
 
+  it('mapGetters (with namespace)', () => {
+    const store = new Vuex.Store({
+      modules: {
+        foo: {
+          namespaced: true,
+          state: { count: 0 },
+          mutations: {
+            inc: state => state.count++,
+            dec: state => state.count--
+          },
+          getters: {
+            hasAny: ({ count }) => count > 0,
+            negative: ({ count }) => count < 0
+          }
+        }
+      }
+    })
+    const vm = new Vue({
+      store,
+      computed: mapGetters('foo', {
+        a: 'hasAny',
+        b: 'negative'
+      })
+    })
+    expect(vm.a).toBe(false)
+    expect(vm.b).toBe(false)
+    store.commit('foo/inc')
+    expect(vm.a).toBe(true)
+    expect(vm.b).toBe(false)
+    store.commit('foo/dec')
+    store.commit('foo/dec')
+    expect(vm.a).toBe(false)
+    expect(vm.b).toBe(true)
+  })
+
   it('mapActions (array)', () => {
     const a = jasmine.createSpy()
     const b = jasmine.createSpy()
@@ -177,4 +263,32 @@ describe('Helpers', () => {
     vm.bar()
     expect(b).toHaveBeenCalled()
   })
+
+  it('mapActions (with namespace)', () => {
+    const a = jasmine.createSpy()
+    const b = jasmine.createSpy()
+    const store = new Vuex.Store({
+      modules: {
+        foo: {
+          namespaced: true,
+          actions: {
+            a,
+            b
+          }
+        }
+      }
+    })
+    const vm = new Vue({
+      store,
+      methods: mapActions('foo/', {
+        foo: 'a',
+        bar: 'b'
+      })
+    })
+    vm.foo()
+    expect(a).toHaveBeenCalled()
+    expect(b).not.toHaveBeenCalled()
+    vm.bar()
+    expect(b).toHaveBeenCalled()
+  })
 })