纯JS实现HTML页三主题切换与明暗模式切换
纯JS实现Markdown预览主题/明暗模式切换
核心规则遵循
- 所有主题类、明暗模式类必须挂载到
<html>根元素(即CSS:root匹配节点),禁止挂载到body或其他子容器,避免选择器匹配失败加载错误的Iti主题配色 - 类名切换仅移除同组(主题组/明暗组)的旧类,根元素原有其他类(如浏览器扩展注入类、自定义功能类)全部保留,不得清空重置
- 类名组合严格符合要求:主题类+明暗类同级共存,例如Empresas暗色模式对应根元素class为
voxel-theme-empresas vscode-dark
页面控件示例
先在页面中加入切换用的下拉框和按钮:
<select id="themeSelect"> <option value="voxel-theme-empresas">Empresas主题</option> <option value="voxel-theme-ion">Ion主题</option> <option value="voxel-theme-iti">Iti主题</option> </select> <button id="modeToggle">切换明暗模式</button>
CSS变量定义示例
按根元素类组合定义对应主题的全局变量即可:
/* Empresas主题 */ :root.voxel-theme-empresas.vscode-light { --primary: #165DFF; --bg: #ffffff; --text: #1d2129; } :root.voxel-theme-empresas.vscode-dark { --primary: #4080FF; --bg: #1d2129; --text: #f2f3f5; } /* Ion主题 */ :root.voxel-theme-ion.vscode-light { --primary: #00B42A; --bg: #f7f8fa; --text: #1d2129; } :root.voxel-theme-ion.vscode-dark { --primary: #00C440; --bg: #17171a; --text: #f2f3f5; } /* Iti主题 */ :root.voxel-theme-iti.vscode-light { --primary: #F53F3F; --bg: #ffffff; --text: #333333; } :root.voxel-theme-iti.vscode-dark { --primary: #F76560; --bg: #232324; --text: #f2f3f5; }
完整JS逻辑
替换原有错误的switchMode实现,加入主题切换逻辑,支持本地存储记忆用户选择:
const root = document.documentElement; // 合法类名配置 const THEME_LIST = ['voxel-theme-empresas', 'voxel-theme-ion', 'voxel-theme-iti']; const MODE_LIST = ['vscode-light', 'vscode-dark']; // 本地存储key const THEME_STORAGE = 'md_preview_theme'; const MODE_STORAGE = 'md_preview_mode'; // 切换主题 function switchTheme(targetTheme) { if (!THEME_LIST.includes(targetTheme)) return; // 仅移除旧主题类,保留其他类 THEME_LIST.forEach(cls => cls !== targetTheme && root.classList.remove(cls)); root.classList.add(targetTheme); localStorage.setItem(THEME_STORAGE, targetTheme); // 同步下拉框状态 const select = document.getElementById('themeSelect'); select && (select.value = targetTheme); } // 切换明暗模式(修正原有操作body的错误逻辑) function switchMode(forceDark) { const isDark = root.classList.contains('vscode-dark'); const targetDark = typeof forceDark === 'boolean' ? forceDark : !isDark; // 仅移除旧模式类 MODE_LIST.forEach(cls => root.classList.remove(cls)); root.classList.add(targetDark ? 'vscode-dark' : 'vscode-light'); localStorage.setItem(MODE_STORAGE, targetDark ? 'dark' : 'light'); } // 初始化 function init() { // 读取本地存储配置,默认Empresas主题+亮色模式 const savedTheme = localStorage.getItem(THEME_STORAGE) || 'voxel-theme-empresas'; const savedMode = localStorage.getItem(MODE_STORAGE) || 'light'; switchTheme(savedTheme); switchMode(savedMode === 'dark'); // 绑定事件 document.getElementById('themeSelect')?.addEventListener('change', e => switchTheme(e.target.value)); document.getElementById('modeToggle')?.addEventListener('click', () => switchMode()); } // DOM就绪后执行初始化 document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', init) : init();
验证方式
切换任意主题+明暗组合后,打开开发者工具查看<html>根标签的class属性,确认类名组合符合预期,且原有class未被清除,页面读取的CSS变量与当前选中主题匹配,不会错误加载Iti主题配色即可。
内容的提问来源于stack exchange,提问作者Oo'-
相关产品推荐
相关产品推荐

