> 技术文档 > uniapp主题切换功能,适配H5、小程序_uniapp主题色切换

uniapp主题切换功能,适配H5、小程序_uniapp主题色切换


实现方法

方法 性能消耗 维护成本 适用场景 内联样式 较高 低 小程序 CSS变量+属性选择器 低 中 H5 混合方案 中等 低 跨平台项目

优势特点

  1. 性能优化:
    1. H5端使用CSS原生变量切换
    2. 小程序端使用高效样式字符串生成
    3. 切换动画流畅
  2. 维护性提升
    1. 主题配置集中管理
    2. 新增主题只需要拓展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.jsstyle/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\'] { /* ……新变量 */ }}

注意事项

  1. :root选择器:用于匹配文档的根元素(在 HTML 文档中即 标签)。它是定义全局 CSS 变量的最佳位置,尤其在主题切换场景中发挥关键作用。
  2. @media all媒体查询:所有设备上都生效
  3. 请不要将index.scss中的代码放到uni.scss中,这样可能导致切换主题时不生效

风车动漫在线观看