文件
shanghaipeiwan/pwuniapp/common/theme.js

239 行
6.8 KiB
JavaScript

/**
* 前端双主题设计系统核心管理模块
* 严格遵照 UI/UX 规范:无 Emoji、纯矢量、高对比度与 WCAG AA 标准
*/
export const THEME_KEYS = {
COOL: 'cool',
WARM: 'warm'
};
export const THEMES = {
[THEME_KEYS.COOL]: {
key: THEME_KEYS.COOL,
name: '冷光暗夜',
description: '深邃暗夜黑与电竞靛蓝流光,专业沉浸质感',
tokens: {
bgPrimary: '#0A0F1D',
bgSurface: '#151D30',
bgSurfaceElevated: '#1E2942',
bgSurfaceGlass: 'rgba(21, 29, 48, 0.85)',
colorBrand: '#6366F1',
colorBrandLight: '#818CF8',
colorBrandGold: '#F59E0B',
colorBrandGlow: 'rgba(99, 102, 241, 0.35)',
colorBrandGradient: 'linear-gradient(135deg, #6366F1, #8B5CF6)',
borderSubtle: '#1E293B',
borderFocus: '#4F46E5',
textPrimary: '#F8FAFC',
textSecondary: '#94A3B8',
textMuted: '#64748B',
shadowBrand: '0 8rpx 24rpx rgba(99, 102, 241, 0.35)',
navBar: {
backgroundColor: '#0A0F1D',
frontColor: '#ffffff'
},
tabBar: {
color: '#94A3B8',
selectedColor: '#6366F1',
backgroundColor: '#151D30',
borderStyle: 'black'
}
}
},
[THEME_KEYS.WARM]: {
key: THEME_KEYS.WARM,
name: '暖阳晨曦',
description: '明亮温润的奶油米白与暖阳曜橙流光,温馨治愈轻快',
tokens: {
bgPrimary: '#FDFBF7',
bgSurface: '#FFFFFF',
bgSurfaceElevated: '#F8F5F0',
bgSurfaceGlass: 'rgba(255, 255, 255, 0.90)',
colorBrand: '#EA580C',
colorBrandLight: '#F97316',
colorBrandGold: '#F59E0B',
colorBrandGlow: 'rgba(234, 88, 12, 0.18)',
colorBrandGradient: 'linear-gradient(135deg, #F97316, #FB923C)',
borderSubtle: '#F0ECE4',
borderFocus: '#EA580C',
textPrimary: '#1C1917',
textSecondary: '#57534E',
textMuted: '#78716C',
shadowBrand: '0 8rpx 24rpx rgba(234, 88, 12, 0.25)',
navBar: {
backgroundColor: '#FDFBF7',
frontColor: '#000000'
},
tabBar: {
color: '#78716C',
selectedColor: '#EA580C',
backgroundColor: '#FFFFFF',
borderStyle: 'white'
}
}
}
};
const STORAGE_KEY = 'peiwan_app_theme';
/**
* 将主题色彩同步应用至小程序与原生顶部导航栏及底部 TabBar
*/
export function applyThemeToNativeUI(themeKey) {
const theme = THEMES[themeKey] || THEMES[THEME_KEYS.COOL];
const { navBar, tabBar } = theme.tokens;
// 1. 设置顶部系统导航栏颜色 (仅在小程序/App支持原生导航栏时生效,防御 H5 与自定义导航)
// #ifndef H5
try {
if (typeof uni !== 'undefined' && typeof uni.setNavigationBarColor === 'function') {
const p = uni.setNavigationBarColor({
frontColor: navBar.frontColor,
backgroundColor: navBar.backgroundColor,
animation: {
duration: 200,
timingFunc: 'easeOut'
},
success: () => {},
fail: () => {}
});
if (p && typeof p.catch === 'function') {
p.catch(() => {});
}
}
} catch (e) {
// 忽略特定页面无系统导航栏异常
}
// #endif
// 2. 设置底部原生 TabBar 菜单颜色 (仅在原生 TabBar 激活时生效,防御使用自定义 TabBar 组件或原生已隐藏)
// #ifndef H5
try {
if (typeof uni !== 'undefined' && typeof uni.setTabBarStyle === 'function') {
const p = uni.setTabBarStyle({
color: tabBar.color,
selectedColor: tabBar.selectedColor,
backgroundColor: tabBar.backgroundColor,
borderStyle: tabBar.borderStyle,
success: () => {},
fail: () => {}
});
if (p && typeof p.catch === 'function') {
p.catch(() => {});
}
}
} catch (e) {
// 忽略非 TabBar 页面抛出的异常
}
// 3. 动态设置窗口底层原生背景色与下拉刷新底色 (彻底消除页面路由切换时的瞬间黑屏闪烁)
try {
if (typeof uni !== 'undefined' && typeof uni.setBackgroundColor === 'function') {
const p = uni.setBackgroundColor({
backgroundColor: theme.tokens.bgPrimary,
backgroundColorTop: theme.tokens.bgPrimary,
backgroundColorBottom: theme.tokens.bgPrimary,
success: () => {},
fail: () => {}
});
if (p && typeof p.catch === 'function') {
p.catch(() => {});
}
}
if (typeof uni !== 'undefined' && typeof uni.setBackgroundTextStyle === 'function') {
const p = uni.setBackgroundTextStyle({
textStyle: themeKey === THEME_KEYS.WARM ? 'dark' : 'light',
success: () => {},
fail: () => {}
});
if (p && typeof p.catch === 'function') {
p.catch(() => {});
}
}
} catch (e) {
// 忽略特定平台背景色设置异常
}
// #endif
// 3. 在 H5 环境下同步在 body 与 documentElement 上添加/移除主题 class,并同步设置 CSS 变量
try {
if (typeof document !== 'undefined') {
if (themeKey === THEME_KEYS.WARM) {
document.body.classList.add('theme-warm');
document.documentElement.classList.add('theme-warm');
document.documentElement.style.setProperty('--nav-bg', navBar.backgroundColor);
document.documentElement.style.setProperty('--nav-color', navBar.frontColor === '#000000' ? '#1C1917' : '#FFFFFF');
} else {
document.body.classList.remove('theme-warm');
document.documentElement.classList.remove('theme-warm');
document.documentElement.style.setProperty('--nav-bg', navBar.backgroundColor);
document.documentElement.style.setProperty('--nav-color', '#F8FAFC');
}
}
} catch (e) {
// 忽略特定平台无 DOM 对象异常
}
}
/**
* 获取当前持久化的主题标识
*/
export function getCurrentThemeKey() {
try {
const saved = uni.getStorageSync(STORAGE_KEY);
if (saved && THEMES[saved]) {
return saved;
}
} catch (e) {
// 忽略异常,降级到默认
}
return THEME_KEYS.WARM;
}
/**
* 获取当前主题配置对象
*/
export function getCurrentTheme() {
const key = getCurrentThemeKey();
return THEMES[key];
}
/**
* 获取当前主题 Tokens
*/
export function getCurrentTokens() {
return getCurrentTheme().tokens;
}
/**
* 切换全局主题并持久化,广播全局事件,同步更新顶部与底部 UI
*/
export function setTheme(themeKey) {
const targetKey = THEMES[themeKey] ? themeKey : THEME_KEYS.COOL;
try {
uni.setStorageSync(STORAGE_KEY, targetKey);
} catch (e) {
// 忽略持久化异常
}
// 同步原生顶部与底部栏色彩
applyThemeToNativeUI(targetKey);
// 广播主题变更事件
try {
uni.$emit('theme-change', targetKey);
} catch (e) {
// 忽略事件抛出异常
}
return THEMES[targetKey];
}
/**
* 获取所有可选主题列表
*/
export function getAvailableThemes() {
return Object.values(THEMES);
}