主题加载
ChikoAdmin 的主题加载机制确保主题在应用启动时能够正确初始化,并提供了优化的加载体验。
加载原理
主题系统在应用启动时按以下顺序执行:
- 读取本地存储 - 从
localStorage获取用户上次设置的主题 - 应用系统偏好 - 如果没有存储的主题,则检测系统主题偏好
- 初始化主题变量 - 设置 CSS 变量和类名
- 同步组件库主题 - 更新 Ant Design 和其他组件库的主题
主题初始化
ThemeProvider
ThemeProvider 是主题系统的核心组件,负责:
- 从本地存储读取主题设置
- 计算实际主题模式(考虑系统偏好)
- 应用主题到 DOM 元素
- 提供主题上下文给子组件
主题初始化完成后,会标记 initialized 状态,避免在主题未准备好时渲染应用。
系统主题监听
项目会自动监听系统主题变化,当系统主题改变时,如果当前设置为跟随系统,会自动切换主题:
// 监听系统主题变化
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handler = (event: MediaQueryListEvent) => {
if (themeMode !== 'system') {
return;
}
changeThemeMode(event.matches ? 'dark' : 'light');
};
mediaQuery.addEventListener('change', handler);
CSS 变量注入
动态 CSS 变量
主题系统会动态生成 CSS 变量并注入到页面中:
// 生成 CSS 变量字符串
const cssVarStr = getCssVarByTokens(tokens);
const darkCssVarStr = getCssVarByTokens(darkTokens);
// 注入到 style 标签
const css = `
:root {
${cssVarStr}
}
`;
const darkCss = `
:root.${DARK_CLASS} {
${darkCssVarStr}
}
`;
主题类名切换
通过添加/移除 CSS 类名来切换主题:
export function toggleCssDarkMode(darkMode = false) {
const htmlElementClassList = document.documentElement.classList;
if (darkMode) {
htmlElementClassList.add(DARK_CLASS);
} else {
htmlElementClassList.remove(DARK_CLASS);
}
}
主题设置初始化
本地存储读取
主题设置从本地存储读取,如果没有则使用默认配置:
export function initThemeSettings() {
const settings = localStg.get('themeSettings') || themeSettings;
return settings;
}
生产环境覆盖
在生产环境中,可以通过 overrideThemeSettings 覆盖某些主题设置:
export const overrideThemeSettings: Partial<App.Theme.ThemeSetting> = {
watermark: {
text: 'ChikoAdmin',
visible: false
}
};
主题颜色生成
颜色调色板
使用 @chiko-admin/color 包自动生成颜色调色板:
function createThemePaletteColors(colors: App.Theme.ThemeColor, recommended = false) {
const colorKeys = Object.keys(colors) as App.Theme.ThemeColorKey[];
const colorPaletteVar = {} as App.Theme.ThemePaletteColor;
colorKeys.forEach(key => {
const colorMap = getColorPalette(colors[key], recommended);
colorPaletteVar[key] = colorMap.get(500)!;
colorMap.forEach((hex, number) => {
colorPaletteVar[`${key}-${number}`] = hex;
});
});
return colorPaletteVar;
}
推荐颜色模式
启用推荐颜色模式后,系统会自动调整颜色以提供更好的视觉体验:
if (state.settings.recommendColor) {
colorValue = getPaletteColorByNumber(color, 500, true);
}
Ant Design 主题同步
主题算法选择
根据当前主题模式自动选择 Ant Design 的主题算法:
export function getAntdTheme(
colors: App.Theme.ThemeColor,
darkMode: boolean,
tokens: App.Theme.ThemeSetting['tokens']
) {
const { darkAlgorithm, defaultAlgorithm } = antdTheme;
const theme: ConfigProviderProps['theme'] = {
algorithm: [darkMode ? darkAlgorithm : defaultAlgorithm],
// ... 其他配置
};
return theme;
}
组件样式定制
为特定组件定制样式:
components: {
Button: {
controlHeightSM: 28
},
Menu: {
itemSelectedBg: bgColor,
darkItemBg: 'transparent'
}
}
性能优化
CSS 变量优化
- 使用 CSS 变量实现主题切换,避免重复的样式计算
- 通过
requestAnimationFrame批量更新 CSS 变量 - 使用 CSS containment 优化重绘
缓存策略
- 主题设置缓存到本地存储
- 避免重复的主题计算
- 使用
useMemo缓存翻译结果
错误处理
主题加载错误
如果主题加载失败,系统会:
- 记录错误信息
- 自动降级到默认主题
- 通知用户并提供重试选项
兜底方案
ThemeFallback 组件在主题出现问题时提供友好的错误提示和恢复选项。