预览
小程序码
浅色
深色
介绍
深色模式(Dark Mode),微信从iOS客户端 7.0.12、Android 7.0.13、ios13开始正式支持 DarkMode,uniapp HBuilder X 3.6.9+ 也从开始,为开发者提供应用内的 DarkMode 适配能力。uniapp 深色模式适配
小程序端、uniapp App端适配深色模式,没有什么难度,通过开启深色模式配置+各页面通过css媒体查询适配深色主题,即可完成。但是对于nvue来说,不支持媒体查询,我们就要另辟蹊径了。下面我们来看看,如何适配。
配置
1. 小程序端开启支持深色模式开关
// manifest.json => mp-weixin
"mp-weixin": {
"darkmode": true, // 开启支持深色模式
"themeLocation": "theme.json", // 深色模式JSON文件,如果 theme.json 在根目录可省略
...
}
2. App端开启支持深色模式开关
// manifest.json => app-plus
"app-plus": {
"darkmode": true, // 开启支持深色模式
"themeLocation": "theme.json", // 深色模式JSON文件,如果 theme.json 在根目录可省略
// ios底部安全区域颜色(⚠️注意:uniapp官方文档说要放在plus属性下,但其实放在app-plus下才会生效)
"safearea": {
"background": "#ffffff",
"backgroundDark": "#1e1e1e", // HBuilderX 3.1.19+支持
"bottom": {
"offset": "auto"
}
}
...
},
// manifest.json => plus
"plus": {
"distribute": {
"apple": {
"UIUserInterfaceStyle": "Automatic", // 不推荐设置设置light或dark后,否则将无法跟随系统
"defaultTheme": "auto" // HBuilderX 3.6.10及以上版本支持
},
"google": {
"defaultNightMode": "auto"
}
}
...
}
3. src 文件夹下新增 theme.json
文件
{
// 浅色模式
"light": {
"navBgColor": "#fff", // 导航栏背景色
"navTxtStyle": "black", // 导航栏文字颜色
"bgColor": "#f5f6f7", // 页面背景色
"bgTxtStyle": "light", // 下拉 loading 的样式,仅支持 dark/light
"bgColorTop": "#eeeeee", // 顶部窗口的背景色(bounce回弹区域)
"bgColorBottom": "#efefef", // 底部窗口的背景色(bounce回弹区域)
"tabFontColor": "#666666", // tabbar 上的文字默认颜色
"tabSelectedColor": "#FF9B35", // tabbar 上的文字选中颜色
"tabBgColor": "#ffffff", // tabbar 背景色
"tabBorderStyle": "white", // tabbar 上边框的颜色,可选值 black/white,也支持其他颜色值
"iconPath1": "/static/xxx.png", // tabbar第二个图标默认路径
"selectedIconPath1": "/static/xxx.png", // tabbar第二个图标选中路径
"iconPath2": "/static/xxx.png",
"selectedIconPath2": "/static/xxx.png"
},
// 深色模式
"dark": {
"navBgColor": "#1d1d1d", // 导航栏背景色
"navTxtStyle": "white", // 导航栏文字颜色
"bgColor": "#1e1e1e", // 页面背景色
"bgTxtStyle": "dark", // 下拉 loading 的样式,仅支持 dark/light
"bgColorTop": "#1e1e1e", // 顶部窗口的背景色(bounce回弹区域)
"bgColorBottom": "#1e1e1e", // 底部窗口的背景色(bounce回弹区域)
"tabFontColor": "#bbb", // tabbar 上的文字默认颜色
"tabSelectedColor": "#FF9B35", // tabbar 上的文字选中颜色
"tabBgColor": "#212121", // tabbar 背景色
"tabBorderStyle": "black", // tabbar 上边框的颜色,可选值 black/white,也支持其他颜色值
"iconPath1": "/static/xxx.png", // tabbar第一个图标默认路径
"selectedIconPath1": "/static/xxx.png", // tabbar第一个图标选中路径
"iconPath2": "/static/xxx.png", // tabbar第二个图标默认路径
"selectedIconPath2": "/static/xxx.png" // tabbar第二个图标选中路径
}
}
4. 修改 pages.json
文件
// 取theme.json配置的相关属性,以@开头
{
...
// 全局,需要才配置
"globalStyle": {
// 导航栏字体颜色
"navigationBarTextStyle": "@navTxtStyle",
// 导航栏背景色
"navigationBarBackgroundColor": "@navBgColor",
// 导航栏背景底色
"backgroundColor": "@bgColor"
},
// 原生tabbar配置,与theme.json对应即可
"tabBar": {
"color": "@tabFontColor",
"selectedColor": "@tabSelectedColor",
"backgroundColor": "@tabBgColor",
"borderStyle": "@tabBorderStyle",
"list": [
{
"selectedIconPath": "@selectedIconPath1",
"iconPath": "@iconPath1",
"pagePath": "pages/xxx",
"text": "首页"
},
{
"selectedIconPath": "@selectedIconPath2",
"iconPath": "@iconPath2",
"pagePath": "pages/xxx",
"text": "我的"
}
]
}
...
}
5. App.vue
<script>
export default {
onLaunch (options) {
/** @⚠️:App端需要调用setUIStyle,否则无法使用深色模式,官方回复下版修复此问题 **/
// #ifdef APP-PLUS
plus.nativeUI.setUIStyle('auto')
// #endif
}
}
</script>
<style lang='scss'>
</style>
6. 自定义导航栏适配深色模式
如果自定义导航栏,时间、电池等文字信息,无法自动变化,我们需要根据当前主题,动态切换。
在 main.js
中,封装一个修改导航栏标题、电量等信息的方法 uni.setNavStyle
,我们可以直接绑定在uni上。
uni.setNavStyle = () => {
const theme = uni.getSystemInfoSync().theme
// App端
// #ifdef APP-PLUS
plus.navigator.setStatusBarStyle(theme === 'dark' ? 'light' : 'dark') // 只支持dark和light
// #endif
// 小程序端
// #ifdef MP-WEIXIN
uni.setNavigationBarColor({
frontColor: theme === 'dark' ? '#fff' : '#000',
backgroundColor: theme === 'dark' ? '#000' : '#fff'
})
// #endif
}
然后在我们有自定义导航栏的vue或nvue文件中,在 onLoad
执行一次 uni.setNavStyle()
,然后调用 uni.onThemeChange
,即每次主题变化时,执行一次 uni.setNavStyle()
<script>
import { mapState } from 'vuex'
export default {
onLoad () {
uni.setNavStyle()
// 用户切换主题,动态修改状态栏颜色
uni.onThemeChange(() => {
uni.setNavStyle()
})
}
}
</script>
7. 页面中通过css媒体查询适配深色模式
在 css 中,小程序端及App端(非nvue)支持通过媒体查询 prefers-color-scheme
适配不同主题,与 Web 中适配方式一致,例如:
/* 浅色模式的样式 start */
.box {
background: #fff;
}
.text {
color: #000;
}
/* 浅色模式的样式 end */
/* 深色模式的样式 start */
@media (prefers-color-scheme: dark) {
.box {
background: #000;
}
.text {
color: #fff;
}
}
/* 深色模式的样式 end */
到这里,小程序或者App(非nvue)端的深色模式就适配完成了,需要⚠️注意的是,小程序中可以边修改边在开发者工具看到深色模式的效果,但是App端(非nvue)需要【云打包】后在手机或者模拟器上才能看到效果。
但是,对于 nvue
的App,打包后也是无法看到效果的,因为nvue是不支持媒体查询的。(详见nvue中css样式注意事项),所以我们需要另辟蹊径。
首先想到的是,给 nvue
的 template
中最外层元素根据当前主题动态添加 class="isDark"
,但是nvue
一开始是不支持 后代选择器
等css选择器的,这点就很糟心了。
还好,在HBuilderX 3.1.0+ 开始支持新的样式编译模式 "nvueStyleCompiler": "uni-app"
(详见# nvue 样式编译模式介绍),该模式可以在 weex
原有样式基础上支持组合选择器(相邻兄弟选择器、普通兄弟选择器、子选择器、后代选择器),这就很舒服了。
所以,刚刚的动态 class
方案,就可以实现了。
8. nvue适配深色模式——设置新的编译模式
在 manifest.json
中,新增 nvueCompiler
属性
...
"app-plus": {
...
//使nvue支持相邻兄弟选择器、普通兄弟选择器、子选择器、后代选择器
"nvueCompiler": "uni-app",
"nvueStyleCompiler": "uni-app"
...
}
...
9. nvue适配深色模式——状态机 store
声明 isDark
首先,我们在store
中声明一个布尔值变量 isDark
,默认值是根据当前主题色判断是否是深色模式
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
isDark: uni.getSystemInfoSync().theme === 'dark'
}
})
export default store
10. nvue适配深色模式——App.vue文件中,监听主题变化,动态修改 store.state.isDark
<script>
// 引入store
import store from './store/index'
export default {
onThemeChange ({theme}) {
// 用户切换主题时,将新的主题存在store里,这也是实现nvue深色模式的关键
store.state.isDark = theme === 'dark'
}
}
</script>
11、nvue适配深色模式——动态class
在文件中,引入 store.state.isDark
或者使用辅助函数 mapState
引入
<template>
<view class="wrap" :class="{ isDark }">
<text class="text">文字</text>
</view>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['isDark'])
}
}
</script>
<style lang='scss' scoped>
/* 浅色模式的样式 start */
.wrap {
background: #fff;
.text {
color: #000;
}
}
/* 浅色模式的样式 end */
/* 深色模式的样式 start */
.isDark {
&.wrap {
background: #000;
.text {
color: #fff;
}
}
}
/* 深色模式的样式 end */
</style>
到这里,小程序 + nvue开发的App就适配了深色模式。