【Vue】RuoYi-Vue vue3版本 字典TypeScrpit化

本文適用于希望將RuoYi-Vue3項(xiàng)目轉(zhuǎn)化為TypeScript版本,或希望將‘字典’功能模塊從RuoYi-Vue3中獨(dú)立出來(lái),并在其他TypeScript項(xiàng)目中使用的同學(xué)。
文章感謝 Ruoyi團(tuán)隊(duì) 原代碼地址項(xiàng)目 RuoYi-Cloud-Vue3

文章環(huán)境說(shuō)明

pagekage version 備注
vue ^3.4.21 這個(gè)都懂得吧
typescript ^5.5.4 同上
pinia ^2.2.2 狀態(tài)管理庫(kù)
pinia-plugin-persistedstate ^3.2.3 狀態(tài)管理庫(kù)持久化/不需要可以不安裝

文章不講解 piniapinia-plugin-persistedstate 使用方法,可以點(diǎn)擊查看官方文檔

先寫一個(gè)判空函數(shù)

如果你已經(jīng)定義了自己的判空函數(shù),那么可以跳過(guò)此段落。如果你還沒(méi)有定義判空函數(shù),可以將以下代碼保存為一個(gè)新文件,并放置在您希望的位置,比如我將它放在了'/src/utils/assert'路徑下。在接下來(lái)的內(nèi)容中,我們將主要使用isEmpty函數(shù),您也可以根據(jù)自己的需要將isEmpty替換為您自己的判空函數(shù)。

// '@/utils/assert'

// 采取類型
const takeType = (data: unknown) => Object.prototype.toString.call(data).slice(8, -1);
// 是否是假值
export const isFakeValue = <T = unknown>(data: T | undefined | null | ''): data is undefined | null | '' =>
  ['', null, undefined].includes(data as any);
// 是不是數(shù)組
export const isArr = <T = any>(data: unknown): data is T[] =>
  typeof Array.isArray === 'undefined' ? takeType(data) === 'Array' : Array.isArray(data);
// 是不是對(duì)象
export const isObj = <T extends Record<string, any> = Record<string, any>>(data: unknown): data is T =>
  takeType(data) === 'Object';
// 是不是空對(duì)象
export const isEmptyObj = (data: unknown): data is {} => isObj(data) && Object.keys(data).length === 0;
// 是不是空數(shù)組
export const isEmptyArr = (data: unknown): data is any[] => isArr(data) && data.length === 0;
// 是不是空,主要使用函數(shù)
export const isEmpty = (data: unknown): boolean => {
  if (isFake(data)) return true;
  const type = takeType(data);
  switch (type) {
    case 'String':
      return (data as string).length === 0;
    case 'Number':
      return (data as number) === 0;
    case 'Object':
      return isEmptyObj(data);
    case 'Array':
      return isEmptyArr(data);
    case 'Boolean':
      return data as boolean;
    case 'Map':
      return (data as Map<any, any>).size === 0;
    case 'Set':
      return (data as Set<any>).size === 0;
    default:
      return false;
  }
};

創(chuàng)建 dictionaryStore

在你所在 store 目錄下創(chuàng)建 dictionaryStore.ts,不多說(shuō)了看注釋吧,記得替加入你的請(qǐng)求函數(shù)!!!!

import { isEmpty } from '#utils/assert'; // 導(dǎo)入空函數(shù) 可以替換你的判空函數(shù)
import { acceptHMRUpdate, defineStore } from 'pinia';

// 以下類型根據(jù)你的項(xiàng)目需求擴(kuò)展

// 字典的 key 和 value 類型定義
export interface IDictionaryValue {
  value: string;
  label: string;
  tagType?: string;
  tagClass?: string;
}

// 字典類型定義,用于存儲(chǔ)字典的 key 和 value
interface IDictionaries {
  key: string;
  value: IDictionaryValue[];
}

// State 類型定義,用于在組件中使用 store 的狀態(tài)和函數(shù)
export interface IDictionaryState {
  dictionaries: IDictionaries[];
}

// 獲取返回的類型
interface GetDictionaryResults {
  dictLabel: string;
  dictValue: string;
  listClass?: string;
  cssClass?: string;
}

export const useDictionaryStore = defineStore('dictionaryStore', {
  // 初始化狀態(tài)
  state: (): IDictionaryState => ({
    dictionaries: []
  }),
  // 定義 actions 方法
  actions: {
    // 獲取字典
    getDict(key: string) {
      if (isEmpty(key)) return null;
      try {
        const results = this.dictionaries.find((item) => item.key === key);
        if (!results) return null;
        return results.value;
      } catch {
        return null;
      }
    },
    // 設(shè)置字典
    setDict(key: string, value: IDictionaryValue[]) {
      if (isEmpty(key)) return;
      this.dictionaries.push({ key, value });
    },
    // 移除字典
    removeDict(key: string) {
      if (isEmpty(key)) return false;
      try {
        const index = this.dictionaries.findIndex((item) => item.key === key);
        if (index === -1) {
          return false;
        } else {
          this.dictionaries.splice(index, 1);
          return true;
        }
      } catch {
        return false;
      }
    },
    // 清空字典列表(重置)
    clearDict() {
      this.dictionaries = [];
    },
    // 獲取字典數(shù)據(jù)(異步)
    async fetchDict(key: string): Promise<IDictionaryValue[] | null> {
      try {
        ////// 此處替換為實(shí)際獲取字典的方法 請(qǐng)求方法 //////
        ////// 此處替換為實(shí)際獲取字典的方法 請(qǐng)求方法//////
        ////// 此處替換為實(shí)際獲取字典的方法 請(qǐng)求方法 //////
        ////// 此處替換為實(shí)際獲取字典的方法 請(qǐng)求方法 //////
        const value = [] as GetDictionaryResults[];
        const v: IDictionaryValue[] = value.map((p) => ({
          label: p.dictLabel,
          value: p.dictValue,
          elTagType: p.listClass,
          elTagClass: p.cssClass,
        }));
        this.setDict(key, v);
        return v;
      } catch {
        return null;
      }
    }
  },
  // 持久化配置,啟用 pinia-plugin-persistedstate 插件后可用 如果不需要就刪掉
  persist: true
});

// HMR 熱更新
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useDictionaryStore, import.meta.hot));
}

創(chuàng)建 useDictionary

在你的習(xí)慣存放hook的位置創(chuàng)建 useDictionary,博主的存放的位置是 src/hook/ 下。不多說(shuō)了看代碼吧

import { ref, type ToRefs, toRefs } from 'vue';

import { type IDictionaryValue, useDictionaryStore } from '#store/modules/dictionaryStore';
import { isEmpty } from '#utils/assert';

interface IUseDictionaryOptions {
  // 重置本次字典?(重置后需要重新拉取字典)
  reset?: boolean;
}

// 字典結(jié)果類型,使用泛型約束字典key的類型,便于ts的類型推斷
type DictionaryResults<T extends string> = {
  [key in T]: IDictionaryValue[];
};

/**
 * 獲取數(shù)據(jù)字典 useDictionary
 * @param dictKey 字典key
 * @param options 配置
 * @returns ToRefs<DictionaryResults<T>>
 */
export default function useDictionary<T extends string>(
  dictKey: T[],
  options?: IUseDictionaryOptions,
): ToRefs<DictionaryResults<T>> {
  // 定義一個(gè)響應(yīng)式變量res,初始值為空對(duì)象,并指定其類型為DictionaryResults<T>
  const res = ref<DictionaryResults<T>>({} as DictionaryResults<T>);
   // 調(diào)用useDictionaryStore鉤子函數(shù),獲取字典存儲(chǔ)Store對(duì)象
  const store = useDictionaryStore();
  // 重置本次字典?(重置后需要重新拉取字典)
  if (options?.reset) {
    // 遍歷dictKey數(shù)組,對(duì)每個(gè)字典類型執(zhí)行store.removeDict操作
    dictKey.forEach((dictType: string) => store.removeDict(dictType));
  }
  return (() => {
   // 遍歷dictKey數(shù)組,對(duì)每個(gè)字典類型執(zhí)行異步操作
    dictKey.forEach(async (dictType: string) => {
      // 將res對(duì)象中對(duì)應(yīng)字典類型的值初始化為空數(shù)組
      res.value[dictType as keyof DictionaryResults<T>] = [];
      // 從store中獲取對(duì)應(yīng)字典類型的值
      const dict = store.getDict(dictType);
      // 判斷獲取到的字典是否為空
      if (isEmpty(dict)) {
        // 如果字典為空,則從服務(wù)器異步拉取字典數(shù)據(jù)
        const data = await store.fetchDict(dictType);
        // 如果拉取到的數(shù)據(jù)不為空,則將其賦值給res對(duì)象中對(duì)應(yīng)字典類型的值
        if (data) {
          res.value[dictType as keyof DictionaryResults<T>] = data;
        }
      } else {
        // 如果字典不為空,則直接將其賦值給res對(duì)象中對(duì)應(yīng)字典類型的值
        res.value[dictType as keyof DictionaryResults<T>] = dict;
      }
    });
    // 使用 toRefs 將其返回,讓它解構(gòu)是還有響應(yīng)式
    return toRefs<DictionaryResults<T>>(res.value);
  })();
}

看看效果

以上基本完成,看看效果 根據(jù)輸入dictkey值返回響應(yīng)對(duì)象

image.png
image.png
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 選擇qi:是表達(dá)式 標(biāo)簽選擇器 類選擇器 屬性選擇器 繼承屬性: color,font,text-align,li...
    love2013閱讀 2,441評(píng)論 0 11
  • 前言 首先??吹竭@篇文章的同學(xué)大家新年好呀,先講一下我為啥要寫這個(gè)小程序,是這樣,我上上個(gè)星期放假回來(lái)就開(kāi)始我的兼...
    零零寫代碼像菜虛困閱讀 542評(píng)論 0 1
  • Web前端技術(shù)由 html、css 和 javascript 三大部分構(gòu)成,是一個(gè)龐大而復(fù)雜的技術(shù)體系,其復(fù)雜程度...
    hnscdg閱讀 708評(píng)論 0 0
  • Web前端技術(shù)由html、css和 javascript三大部分構(gòu)成,是一個(gè)龐大而復(fù)雜的技術(shù)體系,其復(fù)雜程度不低于...
    Hebborn_hb閱讀 341評(píng)論 0 1
  • 我在深夜里想起的故事 都在黑暗中死去了 燈光也是喑啞 飛蛾滿地灰痕 我在失眠里夢(mèng)到的你 都在十九歲時(shí)死去了 埋在盛...
    爾音依舊閱讀 235評(píng)論 0 6

友情鏈接更多精彩內(nèi)容