docs/api/theme-change.md
iOS 13+、Android 10+ 提供了暗黑模式/深色模式,之前的模式称为light,暗黑称为dark。
同时也要注意,低于上述版本的手机,系统层没有暗黑模式概念。
在uni-app x中,有3种主题概念:OSTheme、hostTheme、appTheme。每种主题在不同平台支持度不同,获取、设置和监听变化的方式也不同。
| 主题概念 | 描述 | App | Web | 小程序 | 获取方式 | 设置方式 | 监听变化 |
|---|---|---|---|---|---|---|---|
| osTheme | 手机OS的当前主题 | √ | x | x | uni.getDeviceInfo | - | uni.onOsThemeChange |
| hostTheme | 浏览器或小程序宿主的当前主题 | x | √ | √ | uni.getAppBaseInfo | - | uni.onHostThemeChange |
| appTheme | App当前主题 | √ | X | x | uni.getAppBaseInfo | uni.setAppTheme | uni.onAppThemeChange |
Web和小程序注意:
应用适配暗黑主题,可以选择:
一般情况下,独立设置主题的场景常见于App平台,所以App平台新增了appTheme的概念。appTheme有几个用途:
开发者做主题适配时需考虑的内容范围:
开发者自己的uvue代码 大部分主题通过css设置,有部分ui需要通过组件的属性或内置API的参数来设置。
web和小程序平台可以使用媒体查询来设置,但App平台暂不支持媒体查询。所以跨端的写法是,通过uni.getAppBaseInfo获取主题设置,保存到vue的响应式变量中,模板的class绑定响应式变量实现动态切换class。
在hello uni-app x有示例,其在app.uvue的onLaunch中调用了checkSystemTheme(),该方法来自于/store/index.uts,获取当前的主题设置存放在响应式state.isDarkMode中。
然后在组件components/boolean-data/boolean-data.vue中,设置computed()的isDarkMode,在template中通过响应式变量isDarkMode动态切换class。
pages.json的页面设置,推荐通过theme.json设置
web 端、小程序需要配置 manifest.json 中 web、mp-weixin 根节点的 "darkmode": true。配置后如果不生效请重新编译运行
uni-app x的App和Web平台框架中自带的界面(小程序平台由小程序宿主自行适配,与uni-app x框架无关)
注意:有些平台,os主题变化时会重启App,有些小程序宿主主题变化时会重启小程序,有些则不会。在会重启的场景下,监听主题变化其实没有意义。
<!-- ## uni.setAppTheme(options) @setapptheme -->::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
设置应用主题
uni.setAppTheme,并不会帮助开发者自动实现整个应用的亮/暗主题切换,它的作用是:
当然组件作者也可以不监听onAppThemeChange,而是暴露主题切换API给开发者,由开发者监听主题切换,再调用组件的主题切换API。
目前uni-app x的内置组件和UI相关的API(比如showModal),并不会响应setAppTheme。组件是暴露了样式属性供开发者自行设置,Modal相关API目前没有样式设置,后续会升级支持。
| Web | 微信小程序 | Android | iOS | iOS uni-app x UTS 插件 | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|---|
| <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.18 | 4.18 | 4.18 | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| options | SetAppThemeOptions | 是 | - | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| theme | string | 是 | - | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 | 主题 |
| success | (result: SetAppThemeSuccessResult) => void | 否 | null | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 | 接口调用成功的回调函数 |
| fail | (result: AppThemeFail) => void | 否 | null | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 | 接口调用失败的回调函数 |
| complete | (result: any) => void | 否 | null | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 | 接口调用结束的回调函数(调用成功、失败都会执行) |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| light | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 亮色模式 |
| dark | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 深色模式 |
| auto | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 跟随系统模式 |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| theme | string | 是 | - | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| errCode | number | 是 | - | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 | 错误码 |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| 702001 | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 参数错误 |
| 2002000 | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 未知错误 |
uni.setAppTheme({
theme: "auto",
success: function() {
console.log("设置appTheme为 auto 成功")
},
fail: function(e: IAppThemeFail) {
console.log("设置appTheme为 auto 失败,原因:", e.errMsg)
}
})
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
开启监听应用主题变化
版本历史调整
| Web | 微信小程序 | Android | iOS | iOS uni-app x UTS 插件 | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|---|
| <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.18 | 4.18 | 4.18 | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| callback | (res: AppThemeChangeResult) => void | 是 | - | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| appTheme | string | 是 | - | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 | 应用主题 |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| light | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 亮色模式 |
| dark | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 深色模式 |
| 类型 |
|---|
| number |
//callbackId 用于注销监听
val callbackId = uni.onAppThemeChange((res: AppThemeChangeResult) => {
console.log("onAppThemeChange", res.appTheme)
})
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
取消监听应用主题变化
| Web | 微信小程序 | Android | iOS | iOS uni-app x UTS 插件 | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|---|
| <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | - | 4.18 | 4.18 | 4.18 | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| id | number | 是 | - | Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - |
val callbackId = uni.onAppThemeChange((res: AppThemeChangeResult) => {
console.log("onAppThemeChange", res.appTheme)
})
//...
//...
//注销监听
uni.offAppThemeChange(this.appThemeChangeId)
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
开启监听系统主题变化
| Web | 微信小程序 | Android | iOS | iOS uni-app x UTS 插件 | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|---|
| <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.18 | 4.18 | 4.18 | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| callback | (res: OsThemeChangeResult) => void | 是 | - | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| osTheme | string | 是 | - | Web: x; 微信小程序: x; Android: 4.18; iOS: 4.18; iOS uni-app x UTS 插件: 4.18; HarmonyOS: 4.71; HarmonyOS(Vapor): 5.0 | 系统主题 |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| light | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 亮色模式 |
| dark | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - | 深色模式 |
| 类型 |
|---|
| number |
//callbackId 用于注销监听
val callbackId = uni.onOsThemeChange((res: OsThemeChangeResult)=> {
console.log("onOsThemeChange---", res.osTheme)
})
注意:
dark,更低版本无法获取、监听OS的主题。::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
取消监听系统主题变化
| Web | 微信小程序 | Android | iOS | iOS uni-app x UTS 插件 | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|---|
| <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.18 | 4.18 | 4.18 | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| id | number | 是 | - | Web: x; 微信小程序: x; Android: -; iOS: -; HarmonyOS: - |
val callbackId = uni.onOsThemeChange((res: OsThemeChangeResult)=> {
console.log("onOsThemeChange---", res.osTheme)
})
...
...
//注销监听
uni.offOsThemeChange(callbackId)
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
监听宿主题状态变化。
| Web | 微信小程序 | Android | iOS | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|
| 4.35 | 4.41 | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| callback | (result: OnHostThemeChangeCallbackResult) => void | 是 | - | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| hostTheme | string | 是 | - | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 主题名称 |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| light | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 亮色模式 |
| dark | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 深色模式 |
| 类型 |
|---|
| number |
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
取消监听宿主题状态变化。
| Web | 微信小程序 | Android | iOS | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|
| 4.35 | 4.41 | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| id | number | 是 | - | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - |
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
监听系统主题状态变化。 已废弃,在web、小程序上推荐使用 onHostThemeChange
| Web | 微信小程序 | Android | iOS | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|
| 4.0 | 4.41 | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| callback | (result: OnThemeChangeCallbackResult) => void | 是 | - | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| theme | string | 是 | - | Web: -; 微信小程序: 4.41; Android: x; iOS: x; HarmonyOS: - | 主题名称 |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| light | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 亮色模式 |
| dark | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 深色模式 |
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-theme
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-theme
:::
取消监听系统主题状态变化。 已废弃,在web、小程序上推荐使用 offHostThemeChange
| Web | 微信小程序 | Android | iOS | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|
| 4.0 | 4.41 | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | <a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a> | 4.71 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| callback | (result: OnThemeChangeCallbackResult) => void | 是 | - | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | - |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| theme | string | 是 | - | Web: -; 微信小程序: 4.41; Android: x; iOS: x; HarmonyOS: - | 主题名称 |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| light | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 亮色模式 |
| dark | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 深色模式 |
示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见 ::: preview https://hellouniappx.dcloud.net.cn/web/#/pages/API/theme-change/theme-change
appRedirect https://hellouniappx.dcloud.net.cn/appredirect.html?path=pages/API/theme-change/theme-change
示例
<template>
<view class="uni-padding-wrap">
<!-- #ifdef APP -->
<view class="uni-common-mt item-box">
<text>osTheme:</text>
<text id="theme">{{ osTheme }}</text>
</view>
<!-- #endif -->
<view class="uni-common-mt item-box">
<text>应用当前主题:</text>
<text id="theme">{{ appTheme }}</text>
</view>
<!-- #ifdef APP -->
<view>
<view class="uni-title uni-common-mt">
<text class="uni-title-text"> 修改appTheme主题(此处仅为演示API,本应用并未完整适配暗黑模式) </text>
</view>
</view>
<view class="uni-list uni-common-pl">
<radio-group @change="radioChange" class="radio-group">
<radio class="uni-list-cell uni-list-cell-pd radio" v-for="(item, index) in items" :key="item"
:class="index < items.length - 1 ? 'uni-list-cell-line' : ''" :value="item" :checked="index === current">
{{ item }}
</radio>
</radio-group>
</view>
<!-- #endif -->
</view>
</template>
<script setup lang="uts">
const osThemeChangeId = ref(0)
const appThemeChangeId = ref(0)
const osTheme = ref("light" as string)
const appTheme = ref("light" as string)
const originalTheme = ref("light" as string)
const current = ref(0)
const items = ref([
"light",
"dark",
"auto"
] as string[])
function bindOsThemeChange() : number {
//注册osTheme变化监听
return uni.onOsThemeChange((res : OsThemeChangeResult) => {
osTheme.value = res.osTheme
})
}
function bindAppThemeChange() : number {
// #ifdef APP
//注册appTheme变化监听
return uni.onAppThemeChange((res : AppThemeChangeResult) => {
appTheme.value = res.appTheme
})
// #endif
// #ifdef WEB || MP
return uni.onHostThemeChange((res : OnHostThemeChangeCallbackResult) => {
appTheme.value = res.hostTheme
})
// #endif
}
function setAppTheme(value : string) {
uni.setAppTheme({
theme: value as 'light' | 'dark' | 'auto',
success: function () {
console.log("设置appTheme为", value, "成功")
},
fail: function (e : IAppThemeFail) {
console.log("设置appTheme为", value, "失败,原因:", e.errMsg)
}
})
}
function radioChange(e : UniRadioGroupChangeEvent) {
const theme = e.detail.value
setAppTheme(theme)
uni.showToast({
icon: 'none',
title: '当前选中:' + theme,
})
}
onReady(() => {
uni.getSystemInfo({
success: (res : GetSystemInfoResult) => {
// #ifdef APP
osTheme.value = res.osTheme!
originalTheme.value = res.appTheme!
appTheme.value = res.appTheme == "auto" ? res.osTheme! : res.appTheme!
current.value = items.value.indexOf(res.appTheme!)
// #endif
// #ifdef WEB || MP
appTheme.value = res.hostTheme!
// #endif
}
})
// #ifdef APP
osThemeChangeId.value = bindOsThemeChange()
// #endif
appThemeChangeId.value = bindAppThemeChange()
})
onUnload(() => {
//注销监听
// #ifdef APP
uni.offAppThemeChange(appThemeChangeId.value)
uni.offOsThemeChange(osThemeChangeId.value)
// #endif
// #ifdef WEB || MP
uni.offHostThemeChange(appThemeChangeId.value)
// #endif
//暂时屏蔽 避免5.1安卓设备自动化测试不过
// uni.showToast({
// "position": "bottom",
// "title": "已停止监听主题切换"
// })
})
</script>
<style>
.item-box {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.uni-list-cell {
justify-content: flex-start;
}
</style>
:::
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| errMsg | string | 是 | - | Web: -; 微信小程序: 4.41; Android: -; iOS: -; HarmonyOS: - | 错误信息 |