Files
WAI_Project_UNIX/cool/theme/index.ts

256 lines
5.3 KiB
TypeScript
Raw Normal View History

2025-07-21 16:47:04 +08:00
import { computed, ref } from "vue";
import uniTheme from "@/theme.json";
import { router } from "../router";
2025-07-26 17:42:36 +08:00
import { ctx } from "../ctx";
2025-07-27 22:27:53 +08:00
import { isNull } from "../utils";
2025-07-21 16:47:04 +08:00
// 主题类型定义,仅支持 light 和 dark
type Theme = "light" | "dark";
// 是否为自动主题模式(跟随系统)
export const isAuto = ref(true);
/**
*
* @param key key
* @returns
*/
export function getStyle(key: string): string | null {
// 页面配置
const style = router.route()?.style;
// 页面配置 key 映射
const names = {
bgColor: "backgroundColor",
bgContentColor: "backgroundColorContent",
navBgColor: "navigationBarBackgroundColor",
navTextStyle: "navigationBarTextStyle"
};
// 如果页面配置存在,则使用页面配置
if (style != null) {
if (names[key] != null) {
const val = style[names[key]!] as string | null;
if (val != null) {
return val;
}
}
}
return null;
}
2025-07-26 17:42:36 +08:00
/**
*
* @param name
* @returns
*/
export const getColor = (name: string) => {
2025-07-27 22:27:53 +08:00
if (isNull(ctx.color)) {
2025-07-26 17:42:36 +08:00
return "";
}
return ctx.color[name] as string;
};
2025-07-21 16:47:04 +08:00
/**
* uniapp
*/
export function getConfig(key: string): string {
// 主题配置
const themeVal = ((isDark.value ? uniTheme.dark : uniTheme.light) as UTSJSONObject)[key] as
| string
| null;
// 页面样式
const styleVal = getStyle(key);
return styleVal ?? themeVal ?? "";
}
/**
*
* APP appTheme auto osTheme
* H5/ hostTheme light
*/
const getTheme = () => {
let value: string | null;
// #ifdef APP
const appInfo = uni.getAppBaseInfo();
// @ts-ignore
const appTheme = appInfo.appTheme as string;
2026-01-21 01:37:34 +08:00
// Use fallback or specific API for osTheme if possible, otherwise getSystemInfoSync is the only way for osTheme currently
const sysInfo = uni.getSystemInfoSync();
const osTheme = sysInfo.osTheme!;
2025-07-21 16:47:04 +08:00
// 如果 appTheme 为 auto则跟随系统主题否则使用 appTheme
value = appTheme == "auto" ? osTheme : appTheme;
isAuto.value = appTheme == "auto";
// #endif
// #ifdef H5 || MP
const hostTheme = uni.getAppBaseInfo().hostTheme;
if (hostTheme) {
// 如果有 hostTheme则使用 hostTheme
value = hostTheme;
} else {
// 默认使用 light 主题
value = "light";
}
// #endif
return value as Theme;
};
// 当前主题响应式变量
export const theme = ref<Theme>(getTheme());
/**
*
*/
export const isDark = computed(() => {
return theme.value == "dark";
});
/**
* APP
*/
export const setIsAuto = () => {
// #ifdef APP
isAuto.value = !isAuto.value;
if (isAuto.value) {
// 设置为自动主题,跟随系统
uni.setAppTheme({
theme: "auto"
});
} else {
// 关闭自动,使用当前 theme
setTheme(theme.value);
}
// #endif
};
/**
*
* @param value "light" | "dark"
*/
export const setTheme = (value: Theme) => {
// 如果当前主题与目标主题一致,则不做处理
if (theme.value == value) return;
// 关闭自动主题
isAuto.value = false;
// #ifdef APP
uni.setAppTheme({
theme: value,
success: () => {
// 设置成功后更新 theme
theme.value = value;
}
});
// #endif
// #ifndef APP
theme.value = value;
// #endif
// #ifdef H5
setH5();
// #endif
};
// 设置 H5 下的主题色
export const setH5 = () => {
const bgContentColor = getConfig("bgContentColor");
const tabBgColor = getConfig("tabBgColor");
const navBgColor = getConfig("navBgColor");
const navTextStyle = getConfig("navTextStyle");
document.body.style.setProperty("--background-color-content", bgContentColor);
const tabbar = document.querySelector(".uni-tabbar");
if (tabbar) {
(tabbar as HTMLElement).style.backgroundColor = tabBgColor;
}
const pageHead = document.querySelector(".uni-page-head");
if (pageHead) {
(pageHead as HTMLElement).style.backgroundColor = navBgColor;
(pageHead as HTMLElement).style.color = navTextStyle;
}
const pageHeadBtnPath = document.querySelector(".uni-page-head-btn path");
if (pageHeadBtnPath) {
(pageHeadBtnPath as HTMLElement).style.fill = navTextStyle;
}
window.parent.postMessage(
{
type: "theme-change",
isDark: isDark.value
},
"*"
);
};
/**
*
*/
export const toggleTheme = () => {
if (isDark.value) {
setTheme("light");
} else {
setTheme("dark");
}
};
/**
*
* APP App
* H5/ hostTheme
*/
export const initTheme = () => {
// #ifdef APP-ANDROID || APP-IOS
uni.onOsThemeChange((res) => {
if (isAuto.value) {
setTimeout(() => {
uni.setAppTheme({
theme: res.osTheme,
success: () => {
theme.value = res.osTheme;
}
});
}, 100);
}
});
// 监听 App 主题变化
uni.onAppThemeChange((res) => {
theme.value = res.appTheme;
});
// #endif
// #ifdef MP
uni.onHostThemeChange((res) => {
setTheme(res.hostTheme);
});
// #endif
// #ifdef H5
// 监听父窗口发送的主题变化消息
// [BUG] uni.onHostThemeChange 打包会丢失
// uni.onHostThemeChange((res) => {
// setTheme(res.hostTheme);
// });
window.addEventListener("message", (e) => {
if (e.data?.type == "theme-change") {
setTheme(e.data.isDark ? "dark" : "light");
}
});
// #endif
};