Files
wechat_wc/src/context/ThemeContext.tsx
T
broccoli b19a56003f 添加登录和后端校验
完成后端设计(未在本仓库体现),通过安全的手段完成了登录鉴权
2026-08-06 16:27:36 +08:00

97 lines
3.0 KiB
TypeScript

import { createContext, useContext, useState, useCallback, useEffect } from 'react'
import Taro, { useDidShow } from '@tarojs/taro'
import { getTheme, setTheme as saveTheme, resolveTheme, type ThemeMode } from '../utils/store'
import { applyPageBackground } from '../utils/themeBackground'
interface ThemeContextValue {
theme: ThemeMode
resolvedTheme: 'light' | 'dark'
toggleTheme: () => void
setTheme: (t: ThemeMode) => void
}
const ThemeContext = createContext<ThemeContextValue>({
theme: 'auto',
resolvedTheme: 'light',
toggleTheme: () => {},
setTheme: () => {}
})
export { ThemeContext }
type ThemeChangeListener = (result: { theme?: string }) => void
type ThemeChangeApi = {
onThemeChange?: (listener: ThemeChangeListener) => void
offThemeChange?: (listener: ThemeChangeListener) => void
}
/** 主题广播事件名:自定义 tabBar 等无法继承 React Context 的独立组件通过它同步主题 */
export const THEME_CHANGE_EVENT = 'themeChange'
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, set] = useState<ThemeMode>(getTheme())
const [resolvedTheme, setResolved] = useState<'light' | 'dark'>(resolveTheme(getTheme()))
const updateResolved = useCallback((mode: ThemeMode) => {
setResolved(resolveTheme(mode))
}, [])
const setTheme = useCallback((t: ThemeMode) => {
saveTheme(t)
set(t)
updateResolved(t)
}, [updateResolved])
const toggleTheme = useCallback(() => {
const next = resolvedTheme === 'light' ? 'dark' : 'light'
setTheme(next)
}, [resolvedTheme, setTheme])
// 广播实际生效主题,供 custom-tab-bar 等独立组件订阅
useEffect(() => {
Taro.eventCenter.trigger(THEME_CHANGE_EVENT, resolvedTheme)
}, [resolvedTheme])
// App 启动时立即同步页面背景(自定义导航区在 iOS 上由 backgroundColorTop 控制),
// 避免首屏/切换 tab 时顶部导航区先显示白色再变主题色
useEffect(() => {
applyPageBackground(resolvedTheme)
}, [resolvedTheme])
// 页面每次显示时(从小程序后台切回前台)重新检测系统主题
useDidShow(() => {
if (theme === 'auto') {
setResolved(resolveTheme('auto'))
}
})
// auto模式下监听系统主题变化
useEffect(() => {
if (theme === 'auto') {
// 先同步一次当前系统主题
setResolved(resolveTheme('auto'))
const listener: ThemeChangeListener = (res) => {
setResolved(res.theme === 'dark' ? 'dark' : 'light')
}
const themeApi = Taro as typeof Taro & ThemeChangeApi
themeApi.onThemeChange?.(listener)
return () => {
themeApi.offThemeChange?.(listener)
}
} else {
updateResolved(theme)
}
}, [theme, updateResolved])
return (
<ThemeContext.Provider value={{ theme, resolvedTheme, toggleTheme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export function useThemeContext(): ThemeContextValue {
return useContext(ThemeContext)
}