使用Vue3 + Vuex封装字典工具

1,109 阅读2分钟

在使用Vue开发中经常碰到一些字典转换的问题,如根据字典数据开发的一些选择框,table中根据字段值展示字典的lable等。每次都手写这些选择项或者转换字典值很是麻烦,并且字典改变之后还要修改对应的代码很是不便,所以就想着封装一个字典工具来解决这个问题。

思路

第一步:使用Vuex管理字典数据。

第一步:创建一个DictUtil提供两个方法dictDataUtildictDataLableUtil

  • dictDataUtil: 根据字段类型从Vuex中获取该字典的所有字段项数据
  • dictDataLableUtil: 根据字段类型从Vuex中获取该字典的该字段值对应的lable

第三步:将上面的方法封装成一个插件,安装在项目中,方便在项目中调用。

实现代码

使用Vuex获取存储字典数据

  1. 创建DictStore.ts文件,在DictStore文件中使用Vuex管理字典数据
import { getDictItemsApi } from "@/api/dict";
import { Module } from "vuex";

export interface IDictItem {
  id: string;
  lable: string;
  value: string | number | boolean;
}

// 存储字典数据
export const dicts = new Map<string, IDictItem[]>();

interface IDict {
  [key: string]: Map<string, IDictItem[]>;
}

const DictStoreModule: Module<IDict, any> = {
  state: { dicts },
  getters: {
    getDict:
      (state) =>
      (key: string): IDictItem[] | undefined => {
        const dict = state.dicts.get(key);
        return dict;
      },
  },
  mutations: {
    setDict(state, payload: Map<string, IDictItem[]>): void {
      payload.forEach((v, k) => {
        state.dicts.set(k, v);
      });
    },
    delDict(state, payload: string): boolean {
      return state.dicts.delete(payload);
    },
    clearAll(state: IDict): void {
      return state.dicts.clear();
    },
  },
  actions: {
    fetchDict: async (context, payload: string): Promise<void> => {
      const dict = new Map<string, IDictItem[]>();
      dict.set(payload, []);
      context.commit("setDict", dict);

      const data = await getDictItemsApi(payload);
      dict.set(payload, data);
      context.commit("setDict", dict);
    },
  },
};

export default DictStoreModule;

创建一个字典工具DictUtil,提供dictDataUtildictDataLableUtil方法。

import { IDictItem } from "@/store/modules/DictStore";
import { useStore } from "vuex";

export const dictDataUtil = (dictType: string): IDictItem[] | null => {
  const store = useStore();
  const dictData = store.getters.getDict(dictType);
  if (!dictData) {
    store.dispatch("fetchDict", dictType);
  }
  return dictData;
};

export const dictDataLableUtil = (
  dictType: string,
  dictValue: string | number | boolean
): string | null => {
  const store = useStore();
  const dictData = store.getters.getDict(dictType);
  if (!dictData) {
    store.dispatch("fetchDict", dictType);
  }
  if (dictData) {
    const dictItem = dictData.find((d: IDictItem) => d.value === dictValue);
    if (dictItem) {
      return dictItem.label;
    }
  }
  return null;
};

创建字段插件

dictDataUtildictDataLableUtil方法封装成一个字典插件,以便全局安装

import { App } from "vue";
import { dictDataUtil, dictDataLableUtil } from "@/utils/DictUtil";

const DictInstall = {
  install: (app: App): App<any> => {
    app.mixin({
      methods: {
        dictData: dictDataUtil,
        dictDataLable: dictDataLableUtil,
      },
    });

    return app;
  },
};

export default DictInstall;

安装这个插件

安装字典插件,以方便在项目使用

import DictInstall from "./plugins/DictPlugin";

const app = createApp(App);
app.use(DictInstall).mount("#app");

使用方式

安装插件之后在项目中可以直接使用{{dictData}}{{dictDataLable}}的方式转换字典,如: image.png 效果: image.png

table中可以使用{{dictDataLable}}将字典值转成字段lable image.png

存在的问题

form表单中使用还存在问题,既不能使用{{dictData()}}的方式提供选择框的选项。一种不太优雅的变通方式是使用computeddictDataUtil方法完成的,见下: image.png

image.png

欢迎有解决方法的大佬评论留言。