Next.js 12中如何实现可覆盖的系统暗黑模式动态切换?
在Next.js 12中实现支持系统主题响应的三色切换方案
核心思路
把Tailwind的darkMode固定设为'class',通过JavaScript手动控制dark类的添加/移除,同时监听系统主题变化,仅当用户选择system模式时同步系统设置。这样既兼容手动切换,又能响应系统主题变更。
步骤1:配置Tailwind CSS
在tailwind.config.js里设置:
module.exports = { darkMode: 'class', // 固定用class模式,放弃media自动切换,改由JS控制 // 其他配置... }
步骤2:实现全局主题管理逻辑
在pages/_app.js中添加全局主题控制代码:
import { useEffect, useState } from 'react'; function MyApp({ Component, pageProps }) { const [theme, setTheme] = useState(() => { // 优先取本地存储的用户偏好,默认system return localStorage.getItem('theme') || 'system'; }); useEffect(() => { // 应用主题设置的通用函数 const applyTheme = (systemPrefersDark) => { if (theme === 'dark') { document.documentElement.classList.add('dark'); } else if (theme === 'light') { document.documentElement.classList.remove('dark'); } else { // system模式下跟随系统偏好 systemPrefersDark ? document.documentElement.classList.add('dark') : document.documentElement.classList.remove('dark'); } }; // 获取当前系统主题偏好 const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); applyTheme(mediaQuery.matches); // 仅在system模式下监听系统主题变化 const handleSystemThemeChange = (e) => { if (theme === 'system') { applyTheme(e.matches); } }; mediaQuery.addEventListener('change', handleSystemThemeChange); // 存储用户偏好到本地 localStorage.setItem('theme', theme); // 组件卸载时清理监听 return () => { mediaQuery.removeEventListener('change', handleSystemThemeChange); }; }, [theme]); // 对外暴露主题切换函数,供子组件调用 const toggleTheme = (newTheme) => { setTheme(newTheme); }; return <Component {...pageProps} toggleTheme={toggleTheme} currentTheme={theme} />; } export default MyApp;
步骤3:实现主题切换组件
比如在页面头部添加切换选择器:
function ThemeToggle({ currentTheme, toggleTheme }) { const themeOptions = [ { label: '浅色', value: 'light' }, { label: '深色', value: 'dark' }, { label: '跟随系统', value: 'system' }, ]; return ( <select value={currentTheme} onChange={(e) => toggleTheme(e.target.value)} className="p-2 rounded-md border" > {themeOptions.map(opt => ( <option key={opt.value} value={opt.value}>{opt.label}</option> ))} </select> ); } export default ThemeToggle;
关键注意点
- 不要动态切换Tailwind的
darkMode取值(一会media一会class),否则会导致样式冲突,统一用class模式由JS控制更稳定。 - 监听系统主题变化时,必须判断当前是否处于
system模式,避免手动选择主题后被系统设置覆盖。 - 本地存储的键名要统一,确保页面刷新后能准确恢复用户之前的主题偏好。
内容的提问来源于stack exchange,提问作者Pierre-Luc Beaudoin
相关产品推荐
相关产品推荐

