0x00 前言
本文将對 Vue-Vben-Admin 的狀态管理實作源碼進行分析解讀,耐心讀完,相信您一定會有所收獲!
0x01 資料倉庫
項目狀态管理代碼實作在
src/store/
目錄下, 使用新一代的狀态管理器
Pinia
, 具體特性詳見 官網 。
檔案
src/store/index.ts
中調用
createPinia()
建立一個pinia 執行個體,聲明方法
setupStore()
并導出,在主入口檔案中調用此方法即可将 pinia 執行個體注冊到應用程式中。
同時單獨将 pinia 執行個體導出,用于在
setup()
函數外使用 pinia store 執行個體。
import { createPinia } from 'pinia';
// 建立一個 pinia(根存儲)
const store = createPinia();
// 注冊到應用程式
export function setupStore(app: App<Element>) {
app.use(store);
}
// 單獨将pinia 執行個體導出
export { store };
在
src/store/modules
目錄下,各個檔案中定義不同的 store 執行個體,主要用于項目配置、錯誤日志、國際化、鎖屏、多标簽、菜單路由權限、使用者狀态等狀态管理。
├── store # 資料倉庫
│ ├── index.ts
│ ├── modules
│ │ ├── app.ts # 項目配置
│ │ ├── errorLog.ts # 錯誤日志
│ │ ├── locale.ts # 國際化/多語言
│ │ ├── lock.ts # 系統鎖屏
│ │ ├── multipleTab.ts # 多标簽
│ │ ├── permission.ts # 權限/菜單/路由
│ │ └── user.ts # 使用者狀态
接下來将對每個檔案一一講解。
0x02 app.ts 項目配置
檔案
src\store\modules\app.ts
聲明導出一個store執行個體
useAppStore
、一個方法
useAppStoreWithOut()
用于沒有使用
setup
元件時使用。
// 項目配置存儲執行個體
export const useAppStore = defineStore({
id: 'app', // 也稱為 name,是必要的,Pinia 使用它來将 store 連接配接到 devtools。
state: {},
getters: {}
actions:{}
});
export function useAppStoreWithOut() {
return useAppStore(store);
}
state
狀态對象定義了主題模式、頁面加載狀态、項目配置、菜單狀态快照等。
state: (): AppState => ({
darkMode: undefined, // 主題模式 dark|light
pageLoading: false, // 頁面加載狀态
projectConfig: Persistent.getLocal(PROJ_CFG_KEY), // 項目配置 ProjectConfig
beforeMiniInfo: {}, // BeforeMiniState
}),
projectConfig
屬性用于配置項目内展示的内容、布局、文本等效果,具體配置檔案路徑
src/settings/projectSetting.ts
, 屬性定義由于篇幅原因請直接檢視官網的 項目配置說明 。
projectConfig
的初始化值從緩存中擷取,而不是從檔案中引入,這個後面會有單獨篇幅進行講解。
beforeMiniInfo
屬性用于當視窗縮小時記住菜單狀态,并在恢複視窗時恢複這些狀态(是否折疊、是否分割、類型、模式)。
export interface BeforeMiniState {
menuCollapsed?: boolean; // 菜單折疊
menuSplit?: boolean; // 分割菜單
menuMode?: MenuModeEnum; // 菜單類型
menuType?: MenuTypeEnum; // 菜單模式
}
Getter
Getter
等同于 Store 狀态的計算值(計算屬性)。
getters: {
// 頁面加載狀态
getPageLoading(): boolean {
return this.pageLoading;
},
// 主題模式
getDarkMode(): 'light' | 'dark' | string {
return this.darkMode || localStorage.getItem(APP_DARK_MODE_KEY_) || darkMode;
},
// 菜單狀态快照
getBeforeMiniInfo(): BeforeMiniState {
return this.beforeMiniInfo;
},
// 項目配置
getProjectConfig(): ProjectConfig {
return this.projectConfig || ({} as ProjectConfig);
},
// 頭部配置
getHeaderSetting(): HeaderSetting {
return this.getProjectConfig.headerSetting;
},
// 菜單配置
getMenuSetting(): MenuSetting {
return this.getProjectConfig.menuSetting;
},
// 動畫配置
getTransitionSetting(): TransitionSetting {
return this.getProjectConfig.transitionSetting;
},
// 多标簽配置
getMultiTabsSetting(): MultiTabsSetting {}
return this.getProjectConfig.multiTabsSetting;
},
},
其中
getDarkMode()
根據
state.darkMode
、localStorage 存儲和 配置檔案的定義值darkMode 進行計算。
// src\settings\designSetting.ts
export const darkMode = ThemeEnum.LIGHT;
Actions
actions: {
// 設定頁面加載狀态
setPageLoading(loading: boolean): void {
this.pageLoading = loading;
},
// 設定主題模式 存于`localStorage`中
setDarkMode(mode: ThemeEnum): void {
this.darkMode = mode;
localStorage.setItem(APP_DARK_MODE_KEY_, mode);
},
// 設定頁面加載狀态
setBeforeMiniInfo(state: BeforeMiniState): void {
this.beforeMiniInfo = state;
},
// 設定項目配置 項目自帶的緩存類進行緩存操作
setProjectConfig(config: DeepPartial<ProjectConfig>): void {
this.projectConfig = deepMerge(this.projectConfig || {}, config);
Persistent.setLocal(PROJ_CFG_KEY, this.projectConfig);
},
// 重置路由
async resetAllState() {
resetRouter();
Persistent.clearAll(); // 清空緩存
},
// 使用定時器設定頁面加載狀态
async setPageLoadingAction(loading: boolean): Promise<void> {
if (loading) {
clearTimeout(timeId);
// Prevent flicker 防止閃爍
timeId = setTimeout(() => {
this.setPageLoading(loading);
}, 50);
} else {
this.setPageLoading(loading);
clearTimeout(timeId);
}
},
},
其他
import { APP_DARK_MODE_KEY_, PROJ_CFG_KEY } from '/@/enums/cacheEnum';
// src\enums\cacheEnum.ts
export const APP_DARK_MODE_KEY_ = '__APP__DARK__MODE__';
export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__';