主题切换需按需加载并卸载css样式模块,核心是动态import()加载封装了注入/卸载逻辑的js模块,每次切换前先执行旧卸载函数再加载新主题,避免样式污染和内存泄漏。

在主题切换时按需加载皮肤样式模块,核心是结合 import() 动态导入 + CSS 模块化 + 样式卸载机制。关键不在于“只导入”,而在于“导入新样式前清理旧样式”,避免样式污染和内存残留。
1. 把皮肤样式封装为独立的 CSS 模块文件
每个主题对应一个纯 CSS 文件(如 theme-dark.css、theme-blue.css),并导出一个默认函数用于注入或卸载:
// themes/theme-dark.css.js
export default function loadDarkTheme() {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/css/theme-dark.css';
link.id = 'theme-style';
document.head.appendChild(link);
return () => link.remove();
}
⚠️ 注意:不要直接写 import './theme-dark.css' —— 那会在构建时静态引入,失去“按需”意义。
2. 动态导入 + 执行加载函数,并保留卸载引用
维护一个当前卸载函数的引用,每次切换前先调用它,再加载新主题:
let currentUnload = () => {};
async function switchTheme(themeName) {
// 卸载当前样式
currentUnload();
try {
// 动态导入对应主题模块
const themeModule = await import(`./themes/theme-${themeName}.css.js`);
// 执行加载,并保存其返回的卸载函数
currentUnload = themeModule.default();
} catch (err) {
console.error('主题加载失败:', err);
}
}
// 示例调用
switchTheme('dark'); // 加载深色主题
switchTheme('blue'); // 先卸载 dark,再加载 blue
3. 支持热更新与 SSR 友好处理(可选增强)
若项目使用 Vite 或 Webpack,CSS 文件可直接被 import() 解析(无需 .js 封装),但需确保构建工具配置了 CSS 代码分割:
- Vite 中:直接
import('./themes/theme-dark.css')是合法的,会返回一个 Promise,但不会提供卸载能力 → 建议仍用 .js 封装方式控制生命周期 - 服务端渲染(SSR):首次渲染由服务端决定主题,客户端接管后才启用动态加载;可在 hydration 后再初始化主题逻辑,避免水合不一致
- 添加 loading 状态或过渡 class(如
theme-transition)提升体验,避免样式闪动
4. 进阶:统一主题管理器(推荐中大型项目)
抽离为可复用的 ThemeManager 类,支持注册、监听、批量卸载:
class ThemeManager {
#unloadFn = () => {};
async set(themeKey) {
this.#unloadFn();
const mod = await import(`./themes/${themeKey}.css.js`);
this.#unloadFn = mod.default();
}
destroy() { this.#unloadFn(); }
}
const themeMgr = new ThemeManager();
themeMgr.set('dark');
这样便于配合状态库(Pinia / Zustand)或 React Context 统一管理主题状态。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











