theme-utils.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. /**
  2. * 主题工具函数:检测系统主题、应用主题、监听系统主题变化
  3. */
  4. export type ThemeMode = "light" | "dark" | "system"
  5. /**
  6. * 检测系统是否为深色模式
  7. */
  8. function isSystemDark(): boolean {
  9. if (typeof window === "undefined") return false
  10. return window.matchMedia("(prefers-color-scheme: dark)").matches
  11. }
  12. /**
  13. * 获取系统当前对应的实际主题(light 或 dark)
  14. */
  15. function getSystemTheme(): "light" | "dark" {
  16. return isSystemDark() ? "dark" : "light"
  17. }
  18. /**
  19. * 应用主题到 documentElement
  20. */
  21. export function applyTheme(theme: ThemeMode): void {
  22. if (typeof document === "undefined") return
  23. const html = document.documentElement
  24. html.classList.remove("dark")
  25. let actualTheme = theme
  26. if (theme === "system") {
  27. actualTheme = getSystemTheme()
  28. }
  29. if (actualTheme === "dark") {
  30. html.classList.add("dark")
  31. }
  32. }
  33. /**
  34. * 监听系统主题变化,当主题为system模式时自动切换
  35. * 返回一个取消监听的函数
  36. */
  37. export function watchSystemTheme(onChange: () => void): () => void {
  38. if (typeof window === "undefined") return () => {}
  39. const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
  40. const handler = () => onChange()
  41. if (mediaQuery.addEventListener) {
  42. mediaQuery.addEventListener("change", handler)
  43. return () => mediaQuery.removeEventListener("change", handler)
  44. } else {
  45. // 兼容旧浏览器
  46. mediaQuery.addListener(handler)
  47. return () => mediaQuery.removeListener(handler)
  48. }
  49. }