如何通过导航栏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
相关产品推荐
相关产品推荐

