# 暗黑模式
uview-plus 已提供完整的暗黑模式能力,包含:
- 主题变量(亮/暗两套语义变量)
- 运行时主题状态(系统跟随、手动切换、事件通知)
- 页面与组件的统一接入方式(
upTheme*计算属性与工具方法) - Root 根容器联动(全局背景与变量下发)
本文档对应近期暗黑模式架构升级后的方案,不是旧版“下载主题 scss 文件”流程。
# 1. 架构概览
当前实现采用三层结构:
主题变量层
文件:src/uni_modules/uview-plus/libs/css/theme-vars-core.scss
职责:定义--up-*语义变量,并分别提供:- 默认亮色变量
prefers-color-scheme: dark自动切换变量[data-up-theme='light'|'dark']强制主题变量
运行时主题层
文件:src/uni_modules/uview-plus/libs/theme/theme.js
职责:统一管理主题状态与切换逻辑,支持:system | light | dark偏好模式- 本地存储主题偏好
- 系统主题变化监听(
uni.onThemeChange) - 同步
uni.$u.theme、uni.$u.color、config.color - 发送全局事件
uThemeChange
页面接入层
文件:src/uni_modules/uview-plus/libs/mixin/mixin.js、src/App.up.vue
职责:为页面和组件提供统一可用的主题能力,减少页面重复代码。
# 1.1 uni-app 暗黑模式与 uview-plus 运行时主题的关系
uni-app 原生暗黑模式和 uview-plus 运行时主题不是二选一,而是分工不同:
theme.json/pages.json负责 uni-app 声明式默认主题,适合页面配置层面的默认值。uview-plus 运行时主题系统 负责应用运行过程中的主动同步,包括:
- 系统跟随
- 手动切换
light / dark / system - 本地记忆主题偏好
- 同步导航栏、页面背景、tabBar、组件变量
因此,当运行时主题系统已经介入时,导航栏最终颜色不是单独从 theme.json 读取,而是以当前运行时主题结果为准。默认推荐通过 --up-navbar-bg-color 或对应运行时颜色配置统一管理导航栏背景色。
# 2. 可用 API
uview-plus 安装后可通过 uni.$u 使用以下接口:
// 强制切换当前主题(light / dark)
uni.$u.setTheme('dark')
// 设置主题偏好:system | light | dark
uni.$u.setThemePreference('system')
// 读取偏好与系统主题
uni.$u.getThemePreference()
uni.$u.getSystemTheme()
// 获取当前主题变量映射
uni.$u.getThemeVars()
主题切换后会触发全局事件:
uni.$on('uThemeChange', (payload) => {
// payload.mode: light | dark
// payload.vars: 当前变量字典
})
# 3. 页面推荐写法
页面默认可直接使用 mixin 提供的能力:
upThemeIsDarkupThemeVarsupThemePageStyleupThemeCardStyleupThemeVar(varName, fallback?)
示例:
<template>
<view :style="upThemePageStyle">
<view :style="upThemeCardStyle">内容区域</view>
</view>
</template>
说明:
.vue/uvue页面优先使用 CSS 变量(var(--up-xxx))能力。nvue不支持 CSS 变量时,使用upThemeVar('--up-xxx', '#fallback')获取运行时颜色。
# 4. Root 配合建议
若已启用 Root 注入(见 Root根组件),建议保留根容器统一背景与主题变量下发。
这样可以减少每个页面重复设置背景样式,避免出现“部分页面亮色、部分页面暗色”的断层。
# 5. 组件开发规范(暗黑适配)
组件样式建议遵循:
不直接写死颜色,优先使用语义变量
例如:var(--up-content-color)、var(--up-border-color)、var(--up-bg-color)。组件内含状态色时,优先使用
--up-primary / --up-success / --up-warning / --up-error / --up-info体系。输入类组件必须关注三个对比度
- 文本颜色
- placeholder 颜色
- 边框/背景颜色
对
nvue组件,统一通过运行时颜色映射做兜底。
# 6. 常见问题
# 6.1 页面仍是亮底
- 检查是否使用了页面级硬编码背景色(覆盖了主题变量)。
- 检查根容器是否正确挂载(
App.up.vue+<UpRootView />)。 - 检查主题切换是否实际触发(监听
uThemeChange验证)。
# 6.2 组件在暗黑下“看不见”
常见原因:
- 使用固定浅色文本(如
#333)但背景已变深。 - placeholder 仍是浅灰,不符合暗底对比度。
- 边框和背景使用同色,导致输入框轮廓消失。
建议优先替换为 --up-* 语义变量。
# 7. 迁移建议(从旧方案到新方案)
- 保留旧
theme.scss兼容能力,但新页面优先使用运行时主题方案。 - 页面样式从“手工 if/else 颜色判断”迁移到
upThemePageStyle / upThemeVar。 - 新增组件时直接按语义变量开发,避免后续二次暗黑改造成本。
# 8. 旧版 uni.scss 主题兼容边界
如果项目历史上在 uni.scss 中手写覆盖过 $u-primary、$u-main-color、$u-border-color 等变量,新版本会自动把这些旧值桥接到 light 主题 的 --up-* 变量。
请注意:
- 这些旧
$u-*只定义 light 主题,不会自动生成一套 dark 主题。 - 当主题模式为
dark或系统处于暗色模式时,框架仍使用内置的 dark 语义变量。 - 如果业务需要品牌化 dark 主题,请直接按
--up-*/upThemeVar()方案扩展,而不是继续只维护一份旧$u-*文件。 - 如果旧项目仍在
uni.scss里手写$u-*,请把这些变量写在@import 'uview-plus/theme.scss';之前,确保 bridge 导出的是你的自定义值。 - 如果业务又调用了
setConfig({ color })或等价运行时改色逻辑,显式运行时颜色会优先于旧$u-*bridge。