You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:32:09