App端主题色需通过body class切换并调用原生API强制重绘,而非仅改CSS变量;主题配置统一存于THEME_MAP并持久化至myapp_theme;深色模式须独立定义完整色值方案。

uni-app里改主题色不能只靠CSS变量
直接在:root里写--theme-color: #409eff再用JS改,H5和微信小程序能生效,但App端(尤其是iOS)大概率失效——因为App端的WebView对CSS变量动态更新支持不一致,且uni-app的App编译会做样式预处理。
真正可行的方式是:把主题色作为class名注入到,再通过预设的CSS类控制样式。比如加theme-blue或theme-green,所有颜色相关样式都基于这个class前缀写。
- 主题切换时调用
document.body.classList.replace(),避免残留旧class - 主题色值不要硬编码在JS里,统一放在
const THEME_MAP = { blue: '#409eff', green: '#67c23a' }对象中管理 - App端首次启动时需从
uni.getStorageSync('theme')读取并同步设置class,否则闪白屏
按钮点击切换主题必须手动触发App端原生层重绘
单纯改DOM class后,App端部分组件(如<uni-navbar></uni-navbar>、自定义tabbar、甚至某些view背景)不会自动响应样式变化,尤其iOS平台。需要主动通知原生层刷新。
推荐做法是:在切换主题后,调用uni.setNavigationBarColor(哪怕只是设成当前色),它会强制触发一次原生导航栏重绘;同时对自定义tabbar组件,手动触发this.$forceUpdate()或emit事件通知其重新计算样式。
- Android可略过
setNavigationBarColor,但iOS必须调用,否则状态栏颜色不同步 - 如果用了
uni-app的条件编译#ifdef APP-PLUS,这里就是关键分叉点 - 不要依赖
watch监听theme状态来触发重绘——App端watch可能滞后或丢失
主题配置要存到uni.setStorageSync且兼容多端读取
uni.setStorageSync在H5、小程序、App三端行为不一致:H5存的是localStorage,App存的是原生沙盒文件,小程序是自有存储。但uni.getStorageSync能跨端统一读取,所以它是唯一可靠选择。
注意key名别用theme这种泛用词,建议加前缀避免冲突,比如myapp_theme;值存字符串而非对象,减少序列化风险。
- 切换主题后立即执行
uni.setStorageSync('myapp_theme', 'green'),不要等页面onUnload - App端冷启动时,在
App.vue的onLaunch里读取并应用,否则用户打开App还是默认色 - H5端可额外用
localStorage.setItem双写一份,方便F12调试时快速验证
深色模式适配不是简单反色,得单独定义主题集
很多团队误以为“深色=所有颜色取反”,结果文字灰底看不清、图标消失、阴影全黑。uni-app里更稳妥的做法是:把主题拆成light、dark、blue、purple等独立scheme,每个scheme包含完整的primary、bg、text、border字段。
组件内用computed根据当前theme返回对应色值,例如:themeColors.primary,而不是写v-if="theme === 'dark'"堆逻辑。
- 深色模式下慎用
opacity做半透效果,App端渲染容易发虚 - 系统级深色检测(
uni.getSystemInfoSync().platform === 'ios' && uni.getSystemInfoSync().system.indexOf('iOS 13') !== -1)仅作参考,不建议自动切换,由用户显式选择 - 图标资源最好准备两套(fill / outline),用
v-show切换,比CSS filter更可控


















