全局主题切换需用 ref 包裹主题状态并 provide,配合 useTheme 封装切换逻辑;子组件 inject 时传默认值并 watch 响应变化;CSS 变量动态设置实现样式解耦。

用 Provide 实现全局主题切换,核心不是“把主题塞进去”,而是让所有依赖主题的组件能自动响应变化——这需要状态可变、可监听、且注入路径清晰。
主题状态必须是响应式的(ref 或 reactive)
Provide 的值本身不会自动触发更新。如果传入普通对象或字符串,子组件即使用了 inject 也无法感知变化。
- ✅ 正确做法:用
ref包裹主题名,或用computed派生响应式值 - ❌ 错误做法:直接
provide('theme', 'dark')—— 后续改值不会触发重渲染 - 示例:
const theme = ref('light')<br>provide('theme', theme) // 注入 ref,子组件 inject 后可 .value 读取,也能被 watch
封装主题控制逻辑,避免分散修改
不要让每个页面手动改 theme.value,应统一暴露切换方法,并在内部处理持久化、事件通知等细节。
- 创建一个
useTheme组合式函数,返回theme和toggleTheme - 在
toggleTheme中同步写入 localStorage,并触发自定义事件(如需通知非 Vue 环境) - 根组件中调用并 provide:
const { theme, toggleTheme } = useTheme()<br>provide('theme', theme)<br>provide('toggleTheme', toggleTheme)
子组件安全注入 + 自动响应
inject 不仅要取值,还要确保响应性不丢失;同时建议加默认回退,避免父级未 provide 时报错。
- 使用
inject时传入默认值(如ref('light')),防止未 provide 的边界问题 - 模板中直接绑定:
<div :class="'theme-' + theme.value"> <li>逻辑中需要监听变化时:<code>watch(theme, newTheme => {...}) - 组合式 API 中推荐解构时保留响应性:
const theme = inject('theme', ref('light')) - 在主题切换函数中,向
document.documentElement.style写入变量:document.documentElement.style.setProperty('--bg-color', '#1e1e1e') - CSS 中直接使用:
background-color: var(--bg-color); - 这样无需为每种主题写多套 class,样式层完全解耦
CSS 变量联动:让样式也“活”起来
光切 JS 状态不够,还得驱动 CSS。推荐将主题色映射为 CSS 自定义属性,在根节点动态设置。

















