本文適用于希望將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ù)持久化/不需要可以不安裝 |
文章不講解 pinia 和 pinia-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