diff --git a/doc/@types/index.d.ts b/doc/@types/index.d.ts index fca7e9c..31dd3be 100644 --- a/doc/@types/index.d.ts +++ b/doc/@types/index.d.ts @@ -35,43 +35,42 @@ declare namespace Doc { */ interface state { /** - * 全局 + * 是否 使用 移动设备 访问 + * * 来自服务器端 + * * 这是一个例子 */ - global: { - /** - * 是否 使用 移动设备 访问 - * * 来自服务器端 - * * 这是一个例子 - */ - isMobile: boolean + isMobile: boolean - /** - * 是否 使用 移动设备 访问 - * * 来自 中间件-服务器端 - * * 这是一个例子 - */ - hello: string + /** + * 是否 使用 移动设备 访问 + * * 来自 中间件-服务器端 + * * 这是一个例子 + */ + hello: string - /** - * 测试 热加载 vuex - * * 来自 客户端 - * * 这是一个例子 - */ - testHotLoadingVuex: number + /** + * 测试 热加载 vuex + * * 来自 客户端 + * * 这是一个例子 + */ + testHotLoadingVuex: number - /** - * 初始化 跳转访问 URL - * * 来自服务器端 - * * 这是一个例子 - */ - initialReplaceStateUrl: string - } + /** + * 初始化 跳转访问 URL + * * 来自服务器端 + * * 这是一个例子 + */ + initialReplaceStateUrl: string /** * 编辑器 */ - editor: { + editor?: { test: string + deepTest: { + test1: string + test2: number + } } } @@ -79,14 +78,9 @@ declare namespace Doc { * vuex Mutation-Payload-tree */ interface MutationPayloads { - /** - * 全局 - */ - global: { - SET_IS_MOBILE: boolean - SET_HELLO: { hello: string } - SET_testHotLoadingVuex: { number: number } - } + SET_IS_MOBILE: boolean + SET_HELLO: { hello: string } + SET_testHotLoadingVuex: { number: number } /** * 编辑器 diff --git a/doc/src/envs.ts b/doc/src/envs.ts index 9722fa4..e4ec86d 100644 --- a/doc/src/envs.ts +++ b/doc/src/envs.ts @@ -25,7 +25,7 @@ export interface HostGlobal extends Window { /** * vuex 实例 */ - store: Store + store: Store /** * vue router 实例 diff --git a/doc/src/store/helpers.ts b/doc/src/store/helpers.ts new file mode 100644 index 0000000..c749842 --- /dev/null +++ b/doc/src/store/helpers.ts @@ -0,0 +1,27 @@ +import { Tstore } from '@types' +import { makeWrapper } from 'src/store/utils' + +export const globalHelper = makeWrapper() +export const editorHelper = makeWrapper('editor') + +/** + * 例子 1 + */ +// const store = this.store + +// const getState = globalHelper.createGetState() + +// const deepTest = getState(store, 'editor', 'deepTest') +// const test1 = getState(store, 'editor', 'deepTest', 'test1') +// const test2 = getState(store, 'editor', 'deepTest').test2 + +/** + * 例子 2 + */ +// const store = this.store +// const getEditorState = editorHelper.createGetState() + +// const deepTest = getEditorState(store, 'deepTest') +// const test1 = getEditorState(store, 'deepTest', 'test1') +// const test2 = getEditorState(store, 'deepTest').test2 + diff --git a/doc/src/store/index.ts b/doc/src/store/index.ts index a6a853f..10235c9 100644 --- a/doc/src/store/index.ts +++ b/doc/src/store/index.ts @@ -1,20 +1,16 @@ +import { Tstore } from '@types' + import Vue from 'vue' -import Vuex, { ActionContext, Store } from 'vuex' +import Vuex from 'vuex' import actions from './actions' -import mutations from './mutations' +import mutations, { commit, getState } from './mutations' import getters from './getters' import state from './state' -import { Tstore } from '@types' - Vue.use(Vuex) -function isStore(context: Store) { - return 'strict' in context -} - export function createStore() { - return new Vuex.Store({ + return new Vuex.Store({ state: state(), actions, mutations, @@ -23,76 +19,4 @@ export function createStore() { }) } -type StoreTypeBounds = { global: any } - -function createGetState() { - function getState( - context: Store, - state: K, - ): T['global'][K] - function getState( - context: Store, - namespace: NS, - state: K, - ): T[NS][K] - function getState(context: Store, ...args: any[]): void { - let namespace: string, state: string - if (args.length === 2) { - namespace = args[0] - state = args[1] - } else if (args.length === 1) { - namespace = 'global' - state = args[0] - } - - if (namespace !== 'global') { - return context.state[namespace][state] - } - return context.state[state] - } - - return getState -} - -export const getState = createGetState() - - -function createCommit() { - function commit( - context: Store, - mutation: K, - payload: T['global'][K], - ): void - function commit( - context: Store, - namespace: NS, - mutation: K, - payload: T[NS][K], - ): void - function commit(context: Store, ...args: any[]): void { - let namespace: string, mutation: string, payload: any - if (args.length === 3) { - namespace = args[0] - mutation = args[1] - payload = args[2] - } else if (args.length === 2) { - namespace = 'global' - mutation = args[0] - payload = args[1] - } - - if (namespace !== 'global' && isStore(context)) { - mutation = `${namespace}/${mutation}` - } - return context.commit(mutation, payload) - } - - return commit -} - -export const commit = createCommit() - -// const store = this.store - -// commit(store, 'SET_IS_MOBILE', false) -// commit(store, 'editor', 'test', undefined) \ No newline at end of file +export { commit, getState } \ No newline at end of file diff --git a/doc/src/store/mutations.ts b/doc/src/store/mutations.ts index ba2ae03..14a62eb 100644 --- a/doc/src/store/mutations.ts +++ b/doc/src/store/mutations.ts @@ -1,16 +1,24 @@ -import { Tstore } from "@types" +import { globalHelper } from 'src/store/helpers' -export const mutations: Tstore.createUtils.ModuleMutations = { - SET_IS_MOBILE: (state, isMobile) => { +export const mutations = globalHelper.makeMutations({ + SET_IS_MOBILE: (state, isMobile: boolean) => { console.log('SET_IS_MOBILE', isMobile) state.isMobile = isMobile }, - SET_HELLO: (state, { hello }) => { + SET_HELLO: (state, { hello }: { hello: string }) => { state.hello = hello }, - SET_testHotLoadingVuex: (state, { number }) => { + SET_testHotLoadingVuex: (state, { number }: { number: number }) => { state.testHotLoadingVuex += number * 1 }, -} +}) -export default mutations \ No newline at end of file +export default mutations + +export const commit = globalHelper.createCommit() +export const getState = globalHelper.createGetState() + +// const store = this.store + +// commit(store, 'SET_IS_MOBILE', true) +// commit(store, 'editor', 'test', undefined) \ No newline at end of file diff --git a/doc/src/store/state.ts b/doc/src/store/state.ts index 92985bf..d5f656e 100644 --- a/doc/src/store/state.ts +++ b/doc/src/store/state.ts @@ -1,6 +1,6 @@ import { Tstore } from '@types' -export default function state(): Tstore.state['global'] { +export default function state(): Tstore.state { return { isMobile: false, hello: '', diff --git a/doc/src/store/utils.ts b/doc/src/store/utils.ts new file mode 100644 index 0000000..8833312 --- /dev/null +++ b/doc/src/store/utils.ts @@ -0,0 +1,118 @@ +import { Tstore } from '@types' +import { ActionContext, Store, MutationTree } from 'vuex' + +export type SniffMutationPayload = T extends (state: any, payload: infer P) => any ? P: unknown +export type SniffMutationPayloadTree> = { + [K in keyof M]: SniffMutationPayload +} + +export function makeWrapper(namespace: keyof Tstore.state = ('' as any)) { + function makeMutations>(mutationTree: M) { + return mutationTree + } + + function createCommit>() { + type MutationPayloadTree = SniffMutationPayloadTree + function commit( + context: Store, + mutation: M, + payload: MutationPayloadTree[M], + ): void + function commit

( + context: Store, + path: P, + mutation: M, + payload: MutationPayloadTree[P][M], + ): void + function commit

( + context: Store, + path: P, + path1: P1, + mutation: M, + payload: MutationPayloadTree[P][P1][M], + ): void + function commit

( + context: Store, + path: P, + path1: P1, + path2: P2, + mutation: M, + payload: MutationPayloadTree[P][P1][P2][M], + ): void + function commit(context: Store, ...args: any[]) { + if (!checkStore(context)) return + if (args.length < 2) { + console.error('commit args.length must > 2') + return + } + checkNamespace(namespace, args) + const payload = args.pop() + const paths = args.join('/') + return context.commit(paths, payload) + } + + return commit + } + + function createGetState() { + function getState( + context: Store, + stateKey: K, + ): T[K] + function getState( + context: Store, + stateKey: K, + state1Key: K1, + ): T[K][K1] + function getState( + context: Store, + stateKey: K, + state1Key: K1, + state2Key: K2, + ): T[K][K1][K2] + function getState( + context: Store, + stateKey: K, + state1Key: K1, + state2Key: K2, + state3Key: K3, + ): T[K][K1][K2][K3] + function getState(context: Store, ...args: string[]) { + if (!checkStore(context)) return + checkNamespace(namespace, args) + let result + for (let index = 0; index < args.length; index++) { + const key = args[index]; + if (!result) result = context.state[key] + else result = result[key] + if (!result) return + } + return result + } + return getState + } + + return { + makeMutations, + createCommit, + createGetState, + } +} + +function isStore(context: Store) { + return 'strict' in context +} + +function checkStore(context: Store) { + if (!isStore(context)) { + console.error('checkStore context is not a vuex store!', context) + return false + } + return true +} + +function checkNamespace(namespace: keyof Tstore.state, args: any[]) { + if (namespace) { + args.unshift(namespace) + } +} \ No newline at end of file