perf: Improve the global loading display
parent
e650a0b863
commit
77d40dc763
|
@ -17,7 +17,38 @@ async function initApplication() {
|
||||||
overrides: overridesPreferences,
|
overrides: overridesPreferences,
|
||||||
});
|
});
|
||||||
|
|
||||||
import('./bootstrap').then((m) => m.bootstrap(namespace));
|
// 启动应用并挂载
|
||||||
|
// vue应用主要逻辑及视图
|
||||||
|
const { bootstrap } = await import('./bootstrap');
|
||||||
|
await bootstrap(namespace);
|
||||||
|
|
||||||
|
// 移除并销毁loading
|
||||||
|
destoryAppLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除并销毁loading
|
||||||
|
* 放在这里是而不是放在 index.html 的app标签内,主要是因为这样比较不会生硬,渲染过快可能会有闪烁
|
||||||
|
* 通过先添加css动画隐藏,在动画结束后在移除loading节点来改善体验
|
||||||
|
*/
|
||||||
|
function destoryAppLoading() {
|
||||||
|
// 全局搜索文件 loading.html, 找到对应的节点
|
||||||
|
const loadingElement = document.querySelector('#__app-loading__');
|
||||||
|
if (loadingElement) {
|
||||||
|
loadingElement.classList.add('hidden');
|
||||||
|
const injectLoadingElements = document.querySelectorAll(
|
||||||
|
'[data-app-loading^="inject"]',
|
||||||
|
);
|
||||||
|
// 过渡动画结束后移除loading节点
|
||||||
|
loadingElement.addEventListener(
|
||||||
|
'transitionend',
|
||||||
|
() => {
|
||||||
|
loadingElement.remove();
|
||||||
|
injectLoadingElements.forEach((el) => el?.remove());
|
||||||
|
},
|
||||||
|
{ once: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initApplication();
|
initApplication();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { defineConfig } from '@vben/vite-config';
|
import { defineConfig } from '@vben/vite-config';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
appcation: {
|
application: {
|
||||||
compress: false,
|
compress: false,
|
||||||
compressTypes: ['brotli', 'gzip'],
|
compressTypes: ['brotli', 'gzip'],
|
||||||
importmap: false,
|
importmap: false,
|
||||||
|
|
|
@ -13,6 +13,7 @@ export { toPosixPath } from './path';
|
||||||
export { prettierFormat } from './prettier';
|
export { prettierFormat } from './prettier';
|
||||||
export type { Package } from '@manypkg/get-packages';
|
export type { Package } from '@manypkg/get-packages';
|
||||||
export { consola } from 'consola';
|
export { consola } from 'consola';
|
||||||
|
export { nanoid } from 'nanoid';
|
||||||
export { readPackageJSON } from 'pkg-types';
|
export { readPackageJSON } from 'pkg-types';
|
||||||
export { rimraf } from 'rimraf';
|
export { rimraf } from 'rimraf';
|
||||||
export { $, chalk as colors, fs, spinner } from 'zx';
|
export { $, chalk as colors, fs, spinner } from 'zx';
|
||||||
|
|
|
@ -7,11 +7,11 @@ import { defineConfig, loadEnv, mergeConfig } from 'vite';
|
||||||
import { getApplicationConditionPlugins } from '../plugins';
|
import { getApplicationConditionPlugins } from '../plugins';
|
||||||
import { getCommonConfig } from './common';
|
import { getCommonConfig } from './common';
|
||||||
|
|
||||||
import type { DefineAppcationOptions } from '../typing';
|
import type { DefineApplicationOptions } from '../typing';
|
||||||
|
|
||||||
function defineApplicationConfig(options: DefineAppcationOptions = {}) {
|
function defineApplicationConfig(options: DefineApplicationOptions = {}) {
|
||||||
return defineConfig(async ({ command, mode }) => {
|
return defineConfig(async ({ command, mode }) => {
|
||||||
const { appcation = {}, vite = {} } = options;
|
const { application = {}, vite = {} } = options;
|
||||||
const root = process.cwd();
|
const root = process.cwd();
|
||||||
const isBuild = command === 'build';
|
const isBuild = command === 'build';
|
||||||
const env = loadEnv(mode, root);
|
const env = loadEnv(mode, root);
|
||||||
|
@ -29,11 +29,10 @@ function defineApplicationConfig(options: DefineAppcationOptions = {}) {
|
||||||
mock: true,
|
mock: true,
|
||||||
mode,
|
mode,
|
||||||
turboConsole: false,
|
turboConsole: false,
|
||||||
...appcation,
|
...application,
|
||||||
});
|
});
|
||||||
|
|
||||||
const applicationConfig: UserConfig = {
|
const applicationConfig: UserConfig = {
|
||||||
// },
|
|
||||||
build: {
|
build: {
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
|
@ -44,7 +43,6 @@ function defineApplicationConfig(options: DefineAppcationOptions = {}) {
|
||||||
},
|
},
|
||||||
target: 'es2015',
|
target: 'es2015',
|
||||||
},
|
},
|
||||||
// },
|
|
||||||
esbuild: {
|
esbuild: {
|
||||||
drop: isBuild
|
drop: isBuild
|
||||||
? [
|
? [
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
import { existsSync } from 'node:fs';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
|
||||||
import { fs } from '@vben/node-utils';
|
|
||||||
|
|
||||||
import { defineApplicationConfig } from './application';
|
import { defineApplicationConfig } from './application';
|
||||||
import { defineLibraryConfig } from './library';
|
import { defineLibraryConfig } from './library';
|
||||||
|
|
||||||
|
@ -18,13 +17,19 @@ function defineConfig(options: DefineConfig = {}) {
|
||||||
// 根据包是否存在 index.html,自动判断类型
|
// 根据包是否存在 index.html,自动判断类型
|
||||||
if (type === 'auto') {
|
if (type === 'auto') {
|
||||||
const htmlPath = join(process.cwd(), 'index.html');
|
const htmlPath = join(process.cwd(), 'index.html');
|
||||||
projectType = fs.existsSync(htmlPath) ? 'appcation' : 'library';
|
projectType = existsSync(htmlPath) ? 'application' : 'library';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectType === 'appcation') {
|
switch (projectType) {
|
||||||
return defineApplicationConfig(defineOptions);
|
case 'application': {
|
||||||
} else if (projectType === 'library') {
|
return defineApplicationConfig(defineOptions);
|
||||||
return defineLibraryConfig(defineOptions);
|
}
|
||||||
|
case 'library': {
|
||||||
|
return defineLibraryConfig(defineOptions);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`Unsupported project type: ${projectType}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ function defineLibraryConfig(options: DefineLibraryOptions = {}) {
|
||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: 'src/index.ts',
|
entry: 'src/index.ts',
|
||||||
fileName: () => 'index.mjs',
|
fileName: 'index.mjs',
|
||||||
formats: ['es'],
|
formats: ['es'],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
|
|
|
@ -35,7 +35,7 @@ async function viteExtraAppConfigPlugin({
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async configResolved(config) {
|
async configResolved(config) {
|
||||||
publicPath = config.base;
|
publicPath = ensureTrailingSlash(config.base);
|
||||||
source = await getConfigSource();
|
source = await getConfigSource();
|
||||||
},
|
},
|
||||||
async generateBundle() {
|
async generateBundle() {
|
||||||
|
@ -59,21 +59,13 @@ async function viteExtraAppConfigPlugin({
|
||||||
},
|
},
|
||||||
name: 'vite:extra-app-config',
|
name: 'vite:extra-app-config',
|
||||||
async transformIndexHtml(html) {
|
async transformIndexHtml(html) {
|
||||||
publicPath = publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
|
|
||||||
const hash = `v=${version}-${generatorContentHash(source, 8)}`;
|
const hash = `v=${version}-${generatorContentHash(source, 8)}`;
|
||||||
|
|
||||||
const appConfigSrc = `${publicPath}${GLOBAL_CONFIG_FILE_NAME}?${hash}`;
|
const appConfigSrc = `${publicPath}${GLOBAL_CONFIG_FILE_NAME}?${hash}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
html,
|
html,
|
||||||
tags: [
|
tags: [{ attrs: { src: appConfigSrc }, tag: 'script' }],
|
||||||
{
|
|
||||||
attrs: {
|
|
||||||
src: appConfigSrc,
|
|
||||||
},
|
|
||||||
tag: 'script',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -94,4 +86,8 @@ async function getConfigSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureTrailingSlash(path: string) {
|
||||||
|
return path.endsWith('/') ? path : `${path}/`;
|
||||||
|
}
|
||||||
|
|
||||||
export { viteExtraAppConfigPlugin };
|
export { viteExtraAppConfigPlugin };
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { viteImportMapPlugin } from './importmap';
|
||||||
import { viteInjectAppLoadingPlugin } from './inject-app-loading';
|
import { viteInjectAppLoadingPlugin } from './inject-app-loading';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AppcationPluginOptions,
|
ApplicationPluginOptions,
|
||||||
CommonPluginOptions,
|
CommonPluginOptions,
|
||||||
ConditionPlugin,
|
ConditionPlugin,
|
||||||
LibraryPluginOptions,
|
LibraryPluginOptions,
|
||||||
|
@ -82,7 +82,7 @@ async function getCommonConditionPlugins(
|
||||||
* 根据条件获取应用类型的vite插件
|
* 根据条件获取应用类型的vite插件
|
||||||
*/
|
*/
|
||||||
async function getApplicationConditionPlugins(
|
async function getApplicationConditionPlugins(
|
||||||
options: AppcationPluginOptions,
|
options: ApplicationPluginOptions,
|
||||||
): Promise<PluginOption[]> {
|
): Promise<PluginOption[]> {
|
||||||
// 单独取,否则commonOptions拿不到
|
// 单独取,否则commonOptions拿不到
|
||||||
const isBuild = options.isBuild;
|
const isBuild = options.isBuild;
|
||||||
|
|
|
@ -14,14 +14,14 @@ async function viteInjectAppLoadingPlugin(
|
||||||
): Promise<PluginOption | undefined> {
|
): Promise<PluginOption | undefined> {
|
||||||
const loadingHtml = await getLoadingRawByHtmlTemplate();
|
const loadingHtml = await getLoadingRawByHtmlTemplate();
|
||||||
const envRaw = isBuild ? 'prod' : 'dev';
|
const envRaw = isBuild ? 'prod' : 'dev';
|
||||||
const cacheName = `'__${env.VITE_APP_NAMESPACE}-${envRaw}-theme__'`;
|
const cacheName = `'${env.VITE_APP_NAMESPACE}-${envRaw}-preferences-theme'`;
|
||||||
|
|
||||||
// 获取缓存的主题
|
// 获取缓存的主题
|
||||||
// 保证黑暗主题下,刷新页面时,loading也是黑暗主题
|
// 保证黑暗主题下,刷新页面时,loading也是黑暗主题
|
||||||
const injectScript = `
|
const injectScript = `
|
||||||
<script>
|
<script data-app-loading="inject-js">
|
||||||
var theme = localStorage.getItem(${cacheName});
|
var theme = localStorage.getItem(${cacheName});
|
||||||
document.documentElement.classList.toggle('dark', theme === 'dark');
|
document.documentElement.classList.toggle('dark', /dark/.test(theme));
|
||||||
</script>
|
</script>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -34,11 +34,8 @@ async function viteInjectAppLoadingPlugin(
|
||||||
name: 'vite:inject-app-loading',
|
name: 'vite:inject-app-loading',
|
||||||
transformIndexHtml: {
|
transformIndexHtml: {
|
||||||
handler(html) {
|
handler(html) {
|
||||||
const re = /<div\s*id\s*=\s*"app"\s*>(\s*)<\/div>/;
|
const re = /<body\s*>/;
|
||||||
html = html.replace(
|
html = html.replace(re, `<body>${injectScript}${loadingHtml}`);
|
||||||
re,
|
|
||||||
`<div id="app">${injectScript}${loadingHtml}</div>`,
|
|
||||||
);
|
|
||||||
return html;
|
return html;
|
||||||
},
|
},
|
||||||
order: 'pre',
|
order: 'pre',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<style>
|
<style data-app-loading="inject-css">
|
||||||
html {
|
html {
|
||||||
/* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
|
/* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
|
@ -13,6 +13,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 9999;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -22,6 +26,12 @@
|
||||||
background-color: #f4f7f9;
|
background-color: #f4f7f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 1s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
.loading .dots {
|
.loading .dots {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -96,7 +106,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="loading">
|
<div class="loading" id="__app-loading__">
|
||||||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
||||||
<div class="title"><%= VITE_GLOB_APP_TITLE %></div>
|
<div class="title"><%= VITE_GLOB_APP_TITLE %></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<style>
|
<style data-app-loading="inject-css">
|
||||||
html {
|
html {
|
||||||
/* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
|
/* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
z-index: 9999;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -15,6 +16,14 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #f4f7f9;
|
background-color: #f4f7f9;
|
||||||
|
|
||||||
|
/* transition: all 0.8s ease-out; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 1s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark .loading {
|
.dark .loading {
|
||||||
|
@ -96,7 +105,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="loading">
|
<div class="loading" id="__app-loading__">
|
||||||
<div class="loader"></div>
|
<div class="loader"></div>
|
||||||
<div class="title"><%= VITE_GLOB_APP_TITLE %></div>
|
<div class="title"><%= VITE_GLOB_APP_TITLE %></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import type { PluginOptions } from 'vite-plugin-dts';
|
||||||
|
|
||||||
import viteTurboConsolePlugin from 'unplugin-turbo-console/vite';
|
import viteTurboConsolePlugin from 'unplugin-turbo-console/vite';
|
||||||
|
|
||||||
export interface IImportMap {
|
interface IImportMap {
|
||||||
imports?: Record<string, string>;
|
imports?: Record<string, string>;
|
||||||
scopes?: {
|
scopes?: {
|
||||||
[scope: string]: Record<string, string>;
|
[scope: string]: Record<string, string>;
|
||||||
|
@ -40,7 +40,7 @@ interface CommonPluginOptions {
|
||||||
/** 是否开启devtools */
|
/** 是否开启devtools */
|
||||||
devtools?: boolean;
|
devtools?: boolean;
|
||||||
/** 环境变量 */
|
/** 环境变量 */
|
||||||
env: Record<string, any>;
|
env?: Record<string, any>;
|
||||||
/** 是否构建模式 */
|
/** 是否构建模式 */
|
||||||
isBuild?: boolean;
|
isBuild?: boolean;
|
||||||
/** 构建模式 */
|
/** 构建模式 */
|
||||||
|
@ -49,7 +49,7 @@ interface CommonPluginOptions {
|
||||||
visualizer?: PluginVisualizerOptions | boolean;
|
visualizer?: PluginVisualizerOptions | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AppcationPluginOptions extends CommonPluginOptions {
|
interface ApplicationPluginOptions extends CommonPluginOptions {
|
||||||
/** 开启 gzip 压缩 */
|
/** 开启 gzip 压缩 */
|
||||||
compress?: boolean;
|
compress?: boolean;
|
||||||
/** 压缩类型 */
|
/** 压缩类型 */
|
||||||
|
@ -80,12 +80,12 @@ interface LibraryPluginOptions extends CommonPluginOptions {
|
||||||
injectLibCss?: boolean;
|
injectLibCss?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AppcationOptions extends AppcationPluginOptions {}
|
interface ApplicationOptions extends ApplicationPluginOptions {}
|
||||||
|
|
||||||
interface LibraryOptions extends LibraryPluginOptions {}
|
interface LibraryOptions extends LibraryPluginOptions {}
|
||||||
|
|
||||||
interface DefineAppcationOptions {
|
interface DefineApplicationOptions {
|
||||||
appcation?: AppcationOptions;
|
application?: ApplicationOptions;
|
||||||
vite?: UserConfig;
|
vite?: UserConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,17 +95,18 @@ interface DefineLibraryOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefineConfig = {
|
type DefineConfig = {
|
||||||
type?: 'appcation' | 'auto' | 'library';
|
type?: 'application' | 'auto' | 'library';
|
||||||
} & DefineAppcationOptions &
|
} & DefineApplicationOptions &
|
||||||
DefineLibraryOptions;
|
DefineLibraryOptions;
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
AppcationPluginOptions,
|
ApplicationPluginOptions,
|
||||||
CommonPluginOptions,
|
CommonPluginOptions,
|
||||||
ConditionPlugin,
|
ConditionPlugin,
|
||||||
DefineAppcationOptions,
|
DefineApplicationOptions,
|
||||||
DefineConfig,
|
DefineConfig,
|
||||||
DefineLibraryOptions,
|
DefineLibraryOptions,
|
||||||
|
IImportMap,
|
||||||
ImportmapPluginOptions,
|
ImportmapPluginOptions,
|
||||||
LibraryPluginOptions,
|
LibraryPluginOptions,
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,8 @@ import { defaultPreferences } from './config';
|
||||||
import type { Preferences } from './types';
|
import type { Preferences } from './types';
|
||||||
|
|
||||||
const STORAGE_KEY = 'preferences';
|
const STORAGE_KEY = 'preferences';
|
||||||
|
const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;
|
||||||
|
const STORAGE_KEY_THEME = `${STORAGE_KEY}-theme`;
|
||||||
|
|
||||||
interface initialOptions {
|
interface initialOptions {
|
||||||
namespace: string;
|
namespace: string;
|
||||||
|
@ -36,7 +38,7 @@ function isDarkTheme(theme: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class PreferenceManager {
|
class PreferenceManager {
|
||||||
private cache: StorageManager<Preferences> | null = null;
|
private cache: StorageManager | null = null;
|
||||||
private flattenedState: Flatten<Preferences>;
|
private flattenedState: Flatten<Preferences>;
|
||||||
private initialPreferences: Preferences = defaultPreferences;
|
private initialPreferences: Preferences = defaultPreferences;
|
||||||
private isInitialized: boolean = false;
|
private isInitialized: boolean = false;
|
||||||
|
@ -60,6 +62,8 @@ class PreferenceManager {
|
||||||
*/
|
*/
|
||||||
private _savePreferences(preference: Preferences) {
|
private _savePreferences(preference: Preferences) {
|
||||||
this.cache?.setItem(STORAGE_KEY, preference);
|
this.cache?.setItem(STORAGE_KEY, preference);
|
||||||
|
this.cache?.setItem(STORAGE_KEY_LOCALE, preference.app.locale);
|
||||||
|
this.cache?.setItem(STORAGE_KEY_THEME, preference.app.themeMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +93,7 @@ class PreferenceManager {
|
||||||
* 从缓存中加载偏好设置。如果缓存中没有找到对应的偏好设置,则返回默认偏好设置。
|
* 从缓存中加载偏好设置。如果缓存中没有找到对应的偏好设置,则返回默认偏好设置。
|
||||||
*/
|
*/
|
||||||
private loadCachedPreferences() {
|
private loadCachedPreferences() {
|
||||||
return this.cache?.getItem(STORAGE_KEY);
|
return this.cache?.getItem<Preferences>(STORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -231,8 +235,8 @@ class PreferenceManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 覆盖偏好设置
|
* 覆盖偏好设置
|
||||||
* @param overrides - 要覆盖的偏好设置
|
* overrides 要覆盖的偏好设置
|
||||||
* @param namespace - 命名空间
|
* namespace 命名空间
|
||||||
*/
|
*/
|
||||||
public async initPreferences({ namespace, overrides }: initialOptions) {
|
public async initPreferences({ namespace, overrides }: initialOptions) {
|
||||||
// 是否初始化过
|
// 是否初始化过
|
||||||
|
@ -273,6 +277,8 @@ class PreferenceManager {
|
||||||
this.savePreferences(this.state);
|
this.savePreferences(this.state);
|
||||||
// 从存储中移除偏好设置项
|
// 从存储中移除偏好设置项
|
||||||
this.cache?.removeItem(STORAGE_KEY);
|
this.cache?.removeItem(STORAGE_KEY);
|
||||||
|
this.cache?.removeItem(STORAGE_KEY_THEME);
|
||||||
|
this.cache?.removeItem(STORAGE_KEY_LOCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface StorageItem<T> {
|
||||||
value: T;
|
value: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
class StorageManager<T> {
|
class StorageManager {
|
||||||
private prefix: string;
|
private prefix: string;
|
||||||
private storage: Storage;
|
private storage: Storage;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class StorageManager<T> {
|
||||||
* @param defaultValue 当项不存在或已过期时返回的默认值
|
* @param defaultValue 当项不存在或已过期时返回的默认值
|
||||||
* @returns 值,如果项已过期或解析错误则返回默认值
|
* @returns 值,如果项已过期或解析错误则返回默认值
|
||||||
*/
|
*/
|
||||||
getItem(key: string, defaultValue: T | null = null): T | null {
|
getItem<T>(key: string, defaultValue: T | null = null): T | null {
|
||||||
const fullKey = this.getFullKey(key);
|
const fullKey = this.getFullKey(key);
|
||||||
const itemStr = this.storage.getItem(fullKey);
|
const itemStr = this.storage.getItem(fullKey);
|
||||||
if (!itemStr) {
|
if (!itemStr) {
|
||||||
|
@ -103,7 +103,7 @@ class StorageManager<T> {
|
||||||
* @param value 值
|
* @param value 值
|
||||||
* @param ttl 存活时间(毫秒)
|
* @param ttl 存活时间(毫秒)
|
||||||
*/
|
*/
|
||||||
setItem(key: string, value: T, ttl?: number): void {
|
setItem<T>(key: string, value: T, ttl?: number): void {
|
||||||
const fullKey = this.getFullKey(key);
|
const fullKey = this.getFullKey(key);
|
||||||
const expiry = ttl ? Date.now() + ttl : undefined;
|
const expiry = ttl ? Date.now() + ttl : undefined;
|
||||||
const item: StorageItem<T> = { expiry, value };
|
const item: StorageItem<T> = { expiry, value };
|
||||||
|
|
Loading…
Reference in New Issue