基于vue3.0和element-plus的组件库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

7.2 KiB

Store

Vuex-like state management pattern with Actions, Getters, Mutations, and State classes.


Overview

The store implements a Vuex-like pattern using separate classes for State, Actions, Getters, and Mutations. It uses Vuex's createStore function.


Architecture

Store
├── State (reactive data)
├── Actions (async operations that commit mutations)
├── Mutations (synchronous state changes)
└── Getters (computed values)

State Class

File: /home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts

export class State {
  dict = {
    active_status: {
      A: "启用",
      B: "禁用",
    },
  };
  roles = {};
  menus = [];
  roleRefresh = true;
  style = Styles.plain;
  size = Size.normal;
  actions = [];
  user = {};
  actionPers = {};
  refreshFlags = new Map();
}

State Properties

Property Type Description
dict object Dictionary mappings by code
roles object Role ID to name mapping
menus array User menu permissions
roleRefresh boolean Flag to trigger role refresh
style Styles.plain Current theme style
size Size.normal Current size variant
actions array User action permissions
user object Current user object
actionPers object Action permission mappings
refreshFlags Map Refresh flag tokens per flag name

Actions Class

File: /home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts

export class Actions {
  getDictMap = ({ state, commit }, codes) => {
    if (codes == null) {
      return;
    }
    const arr: Array<any> = [];
    for (let i = 0; i < codes.length; i++) {
      const code = codes[i];
      state.dict[code] || arr.push(code);
    }
    if (arr.length == 0) {
      return;
    }
    getByCodes({ codes: arr.join() }).then((rsp: any) => {
      if (rsp) {
        for (let i = 0; i < arr.length; i++) {
          const key = arr[i];
          const dict = {};
          if (rsp[key]) {
            rsp[key].forEach((item) => {
              dict[item.code] = item.name;
            });
          }
          commit("updateDict", [key, dict]);
        }
      }
    });
  };

  getRoleMap = ({ state, commit }) => {
    state.roleRefresh &&
      mapping().then((rsp) => {
        commit("updateState", ["roles", rsp]);
        commit("updateState", ["roleRefresh", false]);
      });
  };

  getMenus = ({ state, commit }) => {
    getMenus().then((rsp) => commit("updateState", ["menus", rsp]));
  };

  getMyActions = ({ state, commit }, content) => {
    getActions(content).then((rsp) => commit("updateState", ["actions", rsp]));
  };

  login = (store) => {
    const { state, commit } = store;
    state.size.headHeight = state.size.head + "px";
    state.size.asideWidth = state.size.aside + "px";
    commit("initSize");
    this.getMenus(store);
  };

  setRefreshFlag = ({ state, commit }, flags: string[]) => {
    commit("setRefreshFlag", flags);
  };

  unsetRefreshFlag = ({ state, commit }, params: { flags: string[]; token: string }) => {
    commit("unsetRefreshFlag", params);
  };
}

Actions Pattern

  • Actions receive Vuex store object with state, commit, dispatch
  • Actions call API functions and commit mutations
  • Actions never directly modify state
  • Actions can call other actions via dispatch

Key Actions

Action Description
getDictMap Fetches dictionary entries by codes, caches in state
getRoleMap Fetches role mappings if refresh is needed
getMenus Fetches user menu permissions
getMyActions Fetches user action permissions
login Initializes size settings and fetches menus
setRefreshFlag Creates empty refresh flag sets
unsetRefreshFlag Adds token to refresh flag sets

Mutations Class

File: /home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts

export class Mutations {
  updateState = (state, [k, v]) => {
    state[k] = v;
  };

  initSize = (state, param) => {
    const size = state.size;
    const aside = parseInt(size.asideWidth);
    const head = parseInt(size.headHeight);
    const mainPad = parseInt(size.mainPad);
    const searchRow = parseInt(size.searchRowHeight);
    const searchRowPad = parseInt(size.searchRowPad);
    const headRightWidth = parseInt(size.headRightWidth);
    if (param) {
      size.height = param[0];
      size.width = param[1];
    }
    size.mainHeight = Math.floor(size.height - head) + "px";
    size.tableHeight = size.height - 2 * (mainPad + searchRowPad) - 3 - searchRow - head;
    size.pTableHeight = size.tableHeight - size.pageHeight;

    size.headLeftWidth = size.width - aside - headRightWidth - 20 + "px";
  };

  updateDict = (state, param) => {
    state.dict[param[0]] = param[1];
  };

  setRefreshFlag = (state, flags: string[]) => {
    for (const flag of flags) {
      state.refreshFlags.set(flag, new Set());
    }
  };

  unsetRefreshFlag = (state, { flags, token }: { flags: string[]; token: string }) => {
    for (const flag of flags) {
      if (!state.refreshFlags.has(flag)) {
        state.refreshFlags.set(flag, new Set());
      }
      state.refreshFlags.get(flag).add(token);
    }
  };
}

Mutations Pattern

  • Mutations receive state directly
  • Mutations are synchronous
  • Mutations use array destructuring for multiple parameters: ([k, v])
  • Mutations directly modify state properties

Key Mutations

Mutation Description
updateState Generic state update: commit("updateState", ["key", value])
initSize Initializes size-dependent calculated values
updateDict Updates dictionary entry: commit("updateDict", [code, mapping])
setRefreshFlag Creates new refresh flag with empty Set
unsetRefreshFlag Adds token to refresh flag Set

Getters Class

File: /home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts

export class Getters {
  menuIconSize = (state) => {
    return state.size.menuIconSize;
  };
}

Getters Pattern

  • Getters receive state as first parameter
  • Getters compute and return derived values
  • Getters are cached based on dependencies

Store Creation

export interface StoreOptions {
  state?: State;
  getters?: Getters;
  actions?;
  mutations?: Mutations;
  modules?;
  plugins?;
  strict?: boolean;
  devtools?: boolean;
}

export const createStore = (options) => {
  return create(options);
};

Usage in Component

import { createStore } from "vuex";
import { State, Actions, Mutations, Getters } from "./store";

const store = createStore({
  state: new State(),
  getters: new Getters(),
  actions: new Actions(),
  mutations: new Mutations(),
  strict: true,
});

Anti-Patterns

  1. Never modify state directly in actions - Always use commit to call mutations
  2. Do not put async logic in mutations - Mutations must be synchronous
  3. Do not use mutation names as variables - Always use string literals for mutation names
  4. Do not skip the initSize mutation - Without it, derived values like mainHeight will be incorrect

Language: English