uniapp主题切换功能,适配H5、小程序_uniapp主题色切换
实现方法
优势特点
- 性能优化:
- H5端使用CSS原生变量切换
- 小程序端使用高效样式字符串生成
- 切换动画流畅
- 维护性提升
- 主题配置集中管理
- 新增主题只需要拓展vars对象
使用pinia管理主题
第一步、定义主题和CSS变量
state: () => { return { mode: uni.getStorageSync(\'theme\') || \'light\', vars: { light: { \'--primary\': \'#007AFF\', \'--bg\': \'#FFFFFF\' }, dark: { \'--primary\': \'#0BB640\', \'--bg\': \'#1A1A1A\' }, }, }},
第二步、实现主题切换方法
actions: { // 统一切换入口 toggle(themeMode) { // 判断是否传递主题,如果没有则在dark和light之间切换 if (themeMode) { this.mode = themeMode } else { this.mode = this.mode === \'light\' ? \'dark\' : \'light\' } // 本地存储 uni.setStorageSync(\'theme\', this.mode) }, }
第三步、实现原生组件适配
actions: { // 原生组件适配 updateNative() { // 判断终端类型 const isMP = process.env.UNI_PLATFORM?.startsWith(\'mp-\') const vars = this.vars[this.mode] if (isMP) { // 设置顶部导航栏样式 uni.setNavigationBarColor({ backgroundColor: vars[\'--bg\'], frontColor: this.mode === \'dark\' ? \'#ffffff\' : \'#000000\', }) // code…… } }, }
第四步、H5根属性更新
actions: { // H5根属性更新 updateRootAttribute() { const isH5 = process.env.UNI_PLATFORM === \'h5\' if (isH5) { // 更新HTML中的data-theme属性标识 document.documentElement.setAttribute(\'data-theme\', this.mode) } },},
完整代码
import { defineStore } from \'pinia\'export const useThemeStore = defineStore(\'theme\', { state: () => { return { mode: uni.getStorageSync(\'theme\') || \'light\', vars: { light: { \'--primary\': \'#007AFF\', \'--bg\': \'#FFFFFF\' }, dark: { \'--primary\': \'#0BB640\', \'--bg\': \'#1A1A1A\' }, }, } }, actions: { // 统一切换入口 toggle(themeMode) { if (themeMode) { this.mode = themeMode } else { this.mode = this.mode === \'light\' ? \'dark\' : \'light\' } uni.setStorageSync(\'theme\', this.mode) // 多端样式更新 this.updateNative() // #ifdef H5 this.updateRootAttribute() // #endif }, // 原生组件适配 updateNative() { const isMP = process.env.UNI_PLATFORM?.startsWith(\'mp-\') const vars = this.vars[this.mode] if (isMP) { uni.setNavigationBarColor({ backgroundColor: vars[\'--bg\'], frontColor: this.mode === \'dark\' ? \'#ffffff\' : \'#000000\', }) } }, // H5根属性更新 updateRootAttribute() { const isH5 = process.env.UNI_PLATFORM === \'h5\' if (isH5) { document.documentElement.setAttribute(\'data-theme\', this.mode) } }, },})
定义CSS变量
定义CSS变量,H5中使用
/* 多端兼容方案 */:root { // 默认主题(编译时注入小程序) --primary: #007aff; --bg: #ffffff;}// H5动态主题(运行时切换)@media all { [data-theme=\'light\'] { --primary: #007aff; --bg: #ffffff; } [data-theme=\'dark\'] { --primary: #0bb640; --bg: #1a1a1a; }}
在App.vue中导入使用
@import \'@/styles/index.scss\';
创建一个Hook
通过Hook来管理主题的切换、样式格式化等,避免重复导入Store
import { computed } from \'vue\'import { useThemeStore } from \'@/stores/theme\'export const useTheme = () => { const themeStore = useThemeStore() // 响应式主题变量 const themeVars = computed(() => { const result = { // 小程序端需要转换的样式 mpStyle: null, // H5数据属性 dataTheme: themeStore.mode, } if (isMP.value) { result.mpStyle = Object.entries(themeStore.vars[themeStore.mode]) .map(([k, v]) => `${k}:${v}`) .join(\';\') } return result }) const isMP = computed(() => process.env.UNI_PLATFORM?.startsWith(\'mp-\')) return { isMP, toggle: themeStore.toggle, // 切换方法 currentMode: computed(() => themeStore.mode), // 当前模式 themeVars, // 样式绑定对象 }}
在组件中使用
最主要的代码是::style=\"{ ...themeVars.mpStyle }\"
,这样就可以实现在小程序主题切换时变量自动更新
主题切换测试 import { useTheme } from \'@/Hooks/useTheme\'const { themeVars, toggle } = useTheme().container { .box { background-color: var(--bg); font-size: 18px; font-weight: 500; line-height: 32px; color: var(--primary); }}
主题初始化
在App.vue文件中添加如下代码
onLaunch(() => { // 主题初始化 const savedTheme = uni.getStorageSync(\'theme\') if (savedTheme) { themeStore.toggle(savedTheme) }})
优化拓展
添加transition
在css或scss文件中添加如下代码,使主题切换时更加流畅的过渡,避免生硬切换
* { transition: background-color 0.3s, background 0.3s, color 0.3s;}
监听系统主题变化
在App.vue文件中使用uni.onThemeChange
监听系统主题变化,并同步小程序/H5主题变化
onLaunch(() => { // 监听系统主题变化 uni.onThemeChange(({ theme }) => { const systemTheme = theme === \'dark\' ? \'dark\' : \'light\' themeStore.toggle(systemTheme) })})
新增主题?
如果想要新增主题,只需要在stores/theme.js
和style/index.scss
文件中添加对应主题的CSS变量,theme.js中定义小程序的主题,index.scss定义H5的主题,如:
state: () => { return { vars: { light: { \'--primary\': \'#007AFF\', \'--bg\': \'#FFFFFF\' }, dark: { \'--primary\': \'#0BB640\', \'--bg\': \'#1A1A1A\' }, red: { // ……新变量 } }, }},
// H5动态主题(运行时切换)@media all { [data-theme=\'light\'] { --primary: #007aff; --bg: #ffffff; } [data-theme=\'dark\'] { --primary: #0bb640; --bg: #1a1a1a; } [data-theme=\'red\'] { /* ……新变量 */ }}
注意事项
:root
选择器:用于匹配文档的根元素(在 HTML 文档中即 标签)。它是定义全局 CSS 变量的最佳位置,尤其在主题切换场景中发挥关键作用。@media all
媒体查询:所有设备上都生效- 请不要将
index.scss
中的代码放到uni.scss
中,这样可能导致切换主题时不生效