2023-11-13 14:44:42
设计一个支持暗黑主题的CSS-in-JS方案需结合主题变量定义、状态管理、动态样式应用及用户偏好持久化。以下是分步骤的实用实现方案:
1. 定义明暗主题对象创建两套颜色变量,统一管理背景、文字、边框等样式,便于后续切换。
const lightTheme = { background: '#ffffff', text: '#000000', primary: '#007bff', secondary: '#6c757d', border: '#dee2e6'};const darkTheme = { background: '#121212', text: '#ffffff', primary: '#00bcd4', secondary: '#9e9e9e', border: '#333333'};2. 使用React Context管理主题状态通过ThemeContext提供主题数据和切换方法,实现全局状态共享。
import { createContext, useState, useEffect, useContext } from 'react';const ThemeContext = createContext();export const ThemeProvider = ({ children }) => { // 从localStorage或系统偏好初始化主题 const getInitialTheme = () => { const saved = localStorage.getItem('darkMode'); if (saved !== null) return JSON.parse(saved); // 默认跟随系统设置 return window.matchMedia('(prefers-color-scheme: dark)').matches; }; const [darkMode, setDarkMode] = useState(getInitialTheme); const theme = darkMode ? darkTheme : lightTheme; const toggleTheme = () => { const newMode = !darkMode; setDarkMode(newMode); localStorage.setItem('darkMode', JSON.stringify(newMode)); // 持久化 }; return ( <ThemeContext.Provider value={{ theme, darkMode, toggleTheme }}> {children} </ThemeContext.Provider> );};export const useTheme = () => useContext(ThemeContext);3. 在CSS-in-JS中动态应用主题以emotion为例,通过props.theme访问当前主题变量,实现样式动态切换。
import styled from '@emotion/styled';const Container = styled.div` background-color: ${props => props.theme.background}; color: ${props => props.theme.text}; border: 1px solid ${props => props.theme.border}; padding: 16px; transition: background-color 0.3s ease; // 添加过渡效果`;const Button = styled.button` background-color: ${props => props.theme.primary}; color: white; border: none; padding: 8px 16px; cursor: pointer; &:hover { opacity: 0.9; }`;4. 添加主题切换控件在UI中提供按钮,调用toggleTheme方法切换主题。
function App() { const { darkMode, toggleTheme } = useTheme(); return ( <Container> <h1>欢迎使用暗黑模式</h1> <Button onClick={toggleTheme}> 切换到{darkMode ? '亮色' : '暗色'}主题 </Button> </Container> );}5. 持久化用户偏好(可选)通过localStorage保存用户选择的主题,确保刷新后状态不丢失。
// 在ThemeProvider中已实现:useEffect(() => { localStorage.setItem('darkMode', JSON.stringify(darkMode));}, [darkMode]);6. 系统偏好自动适配(可选)监听prefers-color-scheme媒体查询,默认跟随系统设置。
const getInitialTheme = () => { const saved = localStorage.getItem('darkMode'); if (saved !== null) return JSON.parse(saved); return window.matchMedia('(prefers-color-scheme: dark)').matches;};方案优势此方案结构清晰,兼容主流CSS-in-JS库(如styled-components、emotion),适合中大型项目快速集成暗黑主题功能。