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

如何通过导航栏Toggle按钮实现前端dark/light模式切换

前端导航栏明暗主题Toggle实现方案

你现有后端已经完成主题配置能力,前端切换不需要保留原来的整页表单提交逻辑,直接基于你已经写好的Bootstrap开关组件加少量JS即可实现,核心逻辑包含状态初始化、即时切换、本地持久化、可选后端同步四部分。

1. 调整导航栏开关组件

把你原来测试用的开关代码替换成导航栏可用版本,初始状态和后端返回的主题配置绑定:

<!-- 放在导航栏对应位置即可 -->
<div class="custom-control custom-switch d-flex align-items-center mb-0">
    <input type="checkbox" class="custom-control-input" id="themeToggle" 
           @if($siteInfo->ui == 1) checked @endif>
    <label class="custom-control-label" for="themeToggle">
        <i class="fa fa-moon-o" id="themeIcon" class="ml-1"></i>
    </label>
</div>

默认选中状态和后端配置绑定:ui=1(深色模式)时开关默认打开,ui=2(浅色模式)时默认关闭

2. 核心JS实现

把下面的代码放到页面公共JS文件里,或者页面底部的script标签中即可:

const THEME_CONFIG = {
    dark: { code: 1, iconClass: 'fa fa-sun-o', themeClass: 'dark-theme' },
    light: { code: 2, iconClass: 'fa fa-moon-o', themeClass: 'light-theme' }
}
const STORAGE_KEY = 'site_user_theme';

const toggleEl = document.getElementById('themeToggle');
const iconEl = document.getElementById('themeIcon');
const rootEl = document.documentElement; // 主题挂载节点,根据项目实际改body也可以

// 初始化主题:优先读本地存储的用户选择,没有就用后端返回的默认值
function initTheme() {
    const savedTheme = localStorage.getItem(STORAGE_KEY);
    const defaultThemeCode = {{ $siteInfo->ui }};
    const currentTheme = savedTheme ? Number(savedTheme) : defaultThemeCode;
    updateTheme(currentTheme, false);
}

// 更新主题
function updateTheme(themeCode, syncBackend = true) {
    const isDark = themeCode === THEME_CONFIG.dark.code;
    const currentConfig = isDark ? THEME_CONFIG.dark : THEME_CONFIG.light;

    // 切换主题类:如果你的项目是用data-theme属性切换,把下面两行改成 rootEl.dataset.theme = isDark ? 'dark' : 'light'
    rootEl.classList.remove(THEME_CONFIG.dark.themeClass, THEME_CONFIG.light.themeClass);
    rootEl.classList.add(currentConfig.themeClass);

    // 如果你的项目是切换不同CSS文件实现主题,替换上面的类操作,用下面这段
    // const themeCssLink = document.getElementById('theme-style');
    // themeCssLink.href = isDark ? '/css/dark.min.css' : '/css/light.min.css';

    // 更新开关状态和图标
    toggleEl.checked = isDark;
    iconEl.className = currentConfig.iconClass;

    // 持久化到本地存储,用户下次访问直接生效
    localStorage.setItem(STORAGE_KEY, themeCode);

    // 可选:静默同步主题配置到后端,不需要刷新页面
    if (syncBackend) {
        fetch("{{ route('admin.settings.update',$siteInfo->id) }}", {
            method: 'POST',
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: `_method=PUT&ui=${themeCode}`
        }).catch(() => {}); // 容错:同步失败不影响前端切换效果
    }
}

// 绑定开关切换事件
toggleEl.addEventListener('change', () => {
    updateTheme(toggleEl.checked ? THEME_CONFIG.dark.code : THEME_CONFIG.light.code);
});

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initTheme);

3. 适配注意事项

  • 代码里的主题类名、CSS文件路径需要和你现有项目的明暗主题实现保持一致,直接替换对应部分即可
  • 用fetch同步后端的前提是页面head里引入了CSRF meta标签:<meta name="csrf-token" content="{{ csrf_token() }}">,如果没有加这个标签会报419权限错误
  • 如果不需要把用户的前端选择同步到后端,直接删掉updateTheme里的fetch部分即可,本地存储的主题优先级高于后端默认配置,用户切换后刷新页面也不会丢失
  • 你原来后台的两个主题选择表单可以完全保留,作为后台设置站点默认主题的入口,和前端导航栏的切换逻辑不冲突

内容的提问来源于stack exchange,提问作者dlys

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 07:51:24