当前位置: 首页 > news >正文

UniApp === H5实现主题切换

目录

什么是 UniApp 主题?

如何实现 UniApp 主题切换?

1. 创建主题变量文件

2. 引入主题变量文件

3. 使用主题变量

4. 使用pinia管理主题

创建一个Hook

在组件中使用

优化拓展

添加transition

监听系统主题变化

新增主题?


UniApp 是一个跨平台的开发框架,可用于构建 iOS、Android 和 Web 应用程序。UniApp 提供了一个很好的主题切换和自定义样式功能,可以让应用程序在不同的视图之间轻松切换主题或更改颜色,对于用户而言,这是一个很好的体验。本篇文章将为您详细介绍如何在 UniApp 中实现主题切换和自定义样式。

什么是 UniApp 主题?

在 UniApp 中,主题是指应用程序的视觉样式,包括了字体、颜色、边界、背景等。主题可以用于定义全局的样式,同时也可以定义某个组件的样式。在某些情况下,主题可以让开发者更加方便地实现一些设计需求。

如何实现 UniApp 主题切换?

UniApp 中实现主题切换的关键在于使用 CSS 变量。CSS 变量是一种定义一次,随时使用的变量,可以使一些 CSS 属性更具有可重用性和可维护性。在 UniApp 中,CSS 变量可用于定义主题的属性。以下是实现主题切换的步骤:

1. 创建主题变量文件

在项目的顶级目录中添加一个名为 styles/index.scss文件,并在其中声明所需的 CSS 变量。例如:

/* 多端兼容方案 */
:root {// 默认主题(编译时注入小程序)--primary: #007aff;--bg: #ffffff;
}// H5动态主题(运行时切换)
@media all {[data-theme='light'] {--primary: #007aff;--bg: #ffffff;}[data-theme='dark'] {--primary: #0bb640;--bg: #1a1a1a;}
}
  • :root 表示根元素,也就是页面 html 元素,定义的变量是全局变量。
  • CSS 属性选择器匹配那些具有特定属性或属性值的元素。
  • [attr=value]  表示带有以 attr 命名的属性,且属性值为 value 的元素。
  • @media All 就是所有媒介下使用{}中的样式。

2. 引入主题变量文件

在 App.vue 中引入 styles/index.scss文件:

<style lang="scss">
@import '@/styles/index.scss';
</style>

3. 使用主题变量

在组件中使用主题变量,直接使用 var() 函数,传入定义好的 CSS 变量名即可:


// 设置背景颜色为定义好的背景颜色
background-color: var(--bg);
// 设置颜色为定义好的主色调
color: var(--primary);

4. 使用pinia管理主题

创建 /stores/theme 仓库来保存主题切换到数据

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 H5this.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)}},},
})
  • 状态结构

    • mode: 当前主题模式(默认读取本地存储)

    • vars: 定义双主题CSS变量(--primary主色/--bg背景色)

  • 核心方法

    1. toggle(): 切换主题 → 持久化 → 触发多端更新

    2. updateNative(): 小程序导航栏颜色适配

    3. updateRootAttribute(): H5根节点添加data-theme属性

    4. setAttribute() 方法用于设置指定元素上的某个属性值。如果属性已经存在,则更新该值;否则,使用指定的名称和值添加一个新的属性。「这样就可以使用上文中的属性选择器匹配到对应模式,然后更新样式,设置到根元素document 上」

跨端策略

  • 小程序:通过uni.setNavigationBarColor修改导航栏

  • H5:通过[data-theme]属性选择器控制CSS

  • 条件编译:#ifdef H5区分平台逻辑

创建一个Hook

通过Hook来管理主题的切换、样式格式化等,避免重复导入Store

  • 注意这里的 mpStyle 转成了字符串 因为小程序直接绑定对象会有问题 :style={}是解析不了的
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, // 样式绑定对象}
}

一般来说,我们开发中会自动抽象出逻辑函数放在utils中,utils中放的纯逻辑,不存在属于组件的东西,例如methods中定义的纯函数等。而hooks就是在utils的基础上再包一层组件级别的东西(钩子函数等)。例如:我们每次点击button都会弹出一个弹窗,自动显示当前日期。但是我将函数放在util中,每次复用都需要click=handleClick 函数放入日期函数,通过handleClick函数管理utils,那么我不如直接将handleClick也封装起来,下次直接调用,复用了methods注册的环节 hooks和utils的区别: hooks中如果涉及到ref,reactive,computed这些api的数据,那这些数据是具有响应式的,而utils只是单纯提取公共方法就不具备响应式,因此可以把hook理解为加入vue3 api的共通方法

在组件中使用

最主要的代码是::style="{ ...themeVars.mpStyle }",这样就可以实现在小程序主题切换时变量自动更新

<template><view class="container" :style="{ ...themeVars.mpStyle }"><view class="w-150px box"><text>主题切换测试</text><text class="iconfont icon-sousuo"></text><button type="primary" @tap="() => toggle()">切换主题</button></view></view>
</template>
<script setup>
import { useTheme } from '@/Hooks/useTheme'const { themeVars, toggle } = useTheme()
</script>
<style lang="scss" scoped>
.container {.box {background-color: var(--bg);font-size: 18px;font-weight: 500;line-height: 32px;color: var(--primary);}
}
</style>

优化拓展

添加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'] {/* ……新变量 */}
}

css var()
函数的第一个参数是要替换的自定义属性的名称。函数的第二个参数是可选的,用作回退值。如果第一个参数引用的自定义属性无效,则该函数将使用第二个值。


:root是CSS 伪类匹配文档树的根元素

对于 HTML 来说,:root 表示 元素,除了优先级更高之外,与 html 选择器相同

相关文章:

  • [创业之路-376]:企业战略管理案例分析-战略制定/设计-市场洞察“五看”:看宏观之当前的社会发展趋势与战略应对
  • 开源与闭源之争:AI时代的创新博弈与未来抉择
  • 【Linux手册】Linux权限:系统世界的“门禁卡”
  • pytest+allure+allure-pytest 报告输出遇到的问题汇总
  • 讯飞AI相关sdk集成springboot
  • 在UniApp中开发微信小程序实现图片、音频和视频下载功能
  • C++ 内存管理与单例模式剖析
  • 5.24 打卡
  • 【Qt】Qt 5.9.7使用MSVC2015 64Bit编译器
  • Spring AI 使用教程
  • 听课笔记之中国式现代化导论
  • Python应用字符串格式化初解
  • ubuntu 安装latex
  • 批量打印的趣事
  • 接口性能测试-工具JMeter的学习
  • ModbusRTU转profibusDP网关与RAC400控制器快速通讯
  • vitepress | 文档:展示与说明只写一次,使用vitepress-deme-preview插件
  • redis的AOF恢复数据
  • 【编译原理】语法分析方法总结
  • 医疗AI项目文档编写核心要素硬核解析:从技术落地到合规实践
  • 用花生壳做网站/如何做网络销售产品
  • 网站空间 ASP/谷歌海外推广
  • 女人和男人做爰有毒网站/ios aso优化工具
  • 临沂网站制作培训/今天的新闻是什么
  • 兖州市做网站/seo是什么意思网络用语
  • 找个人做网站还是找企业做网站/关键词怎样做优化排名