uniapp换肤最佳实践

前言

换肤是对应用的主题进行切换。需要在不修改代码和结构的前提下,通过动态切换一套样式规则,来改变应用的整体视觉外观,从而为用户提供不同的视觉体验。

而在uniapp中实现换肤,就需要考虑不同平台的实现,本文将介绍一种比较通用的最佳解决方案。

主要亮点有:

  1. 主题色后台进行不同平台配置,通过接口获取
  2. 无需使用类名切换,直接使用变量
  3. 可以利用主题色,衍生出颜色色阶,无需额外定义

在线预览:

接下来话不多说,开始实践部分。

1. 整体实现方式

整体流程梳理:

  1. 后台定义主题色等颜色
  2. 接口请求主题色,转换成CSS变量。注意: 主题色需要转换成rgb,用于衍生出其他颜色色阶, 如--mainColor:#FF4757, --mainRgbColor:255,71,87
  3. 页面根元素绑定,style="--mainColor:#FF4757"
  4. 页面使用,color: var(--mainColor);background: rgba(--mainRgbColor, 0.5)

说明:通用标签的背景色是根据主题色衍生出来的,这里就需要转换成rgb的形式进行使用。

2. 案例说明

接下来我们使用uniapp+vue3+pinia进行案例演示,包括编译后的app、h5、小程序进行实践。

我们整体代码实现思路是:通过pinia进行整体的设置和存储,接口获取时,我们需要额外计算出主题色的rgb

2.1 pinia设置和存储

我们使用pinia进行统一管理我们的换肤颜色。

ini 复制代码
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useThemeStore = defineStore(
  'theme',
  () => {
    const themeInfo = ref(`--bg:#F8F8F8;--mainColor:#FF4757;--mainRgbColor:255,71,87;--subColor:#FFECED;--priceColor:#FF3838;`);

    const setTheme = (val: string) => {
      themeInfo.value = val;
    };

    const resetTheme = () => {
      themeInfo.value = '';
    };

    return {
      themeInfo,
      setTheme,
      resetTheme,
    };
  },
  {
    persist: true
  }
);

2.2 接口请求

我们需要请求自己平台的主题色,进行设置存储。需要将主题色进行转换成rgb形式,方便后续使用。

注意:如果在less中,我们可以使用fade进行rgba的操作,问题是fade函数不支持变量形式,仅仅只能用fade(#FFFFFF,0.2)。 如果使用变量,我们只能转换成rgb的字符,利用rgba实现

js 复制代码
import { useThemeStore } from '@/store';

const hexToRgbStr = (hex: string): string => {
  try {
    // 扩展 3 位格式到 6 位
    const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    hex = hex.replace(shorthandRegex, (m, r, g, b) => {
      return r + r + g + g + b + b;
    });
    // 解析 6 位 HEX 格式
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    if (!result) return ''
    return `${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)}`;

  } catch (error) {
    return ''
  }
}


const handleChange = () => {
  const mainColor = '#FF4757'
  const mainRgbColor = hexToRgbStr(mainColor)
  const colorStr = `--mainColor:${mainColor};--mainRgbColor:${mainRgbColor};--subColor:#FFECED;--priceColor:#FF3838;`
  useThemeStore().setTheme(colorStr)
}

2.3 页面使用

页面使用需要在页面的根元素绑定style,这样就可以在css中使用颜色变量了。

js 复制代码
<div :style="useThemeStore().themeInfo"></div>
css 复制代码
.main {
  color: var(--mainColor);
  background: rgba(var(--mainRgbColor),0.3);
}

2.4 一点开发优化

我们在使用css的时候,会一直使用var,我们希望用更简单的方式进行书写。例如:

scss 复制代码
.main {
  color: $color-theme;
  background: rgba($color-rgb-theme,0.3);
}

这种写法让我们的开发更加舒服,那么怎么去实现这样呢?也很简单,我们只需要定义一个通用的skin.scss,将这些变量定义进去,全局引入即可使用。

下面介绍两个引入方案:

2.4.1 使用vite全局引入

方案一:

  1. 定义skin.scss,定义变量
  2. 如果直接引入到页面会报错,我们直接在vite.config.ts中声明引入
  3. 页面直接使用

如果我们不想使用var()这种形式,需要在vite.config.ts中声明提前加载的css:

ts 复制代码
css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/skin.scss";` // 全局注入
      }
    }
  }

skin.scss:

scss 复制代码
$color-bg: var(--bg);
$color-theme: var(--mainColor);
$color-rgb-theme: var(--mainRgbColor);
$color-theme-d: var(--subColor);
$color-price: var(--priceColor);

这样就可以使用$形式,可以去除var这种写法。

css 复制代码
.main {
  color: $color-theme;
}

2.4.2 使用uni.scss引入

方案二:

我们需要使用到uni.scss,它是一个特殊文件,在代码中无需 import 这个文件即可在scss代码中使用这里的样式变量。uni-app的编译器在webpack配置中特殊处理了这个uni.scss,使得每个scss文件都被注入这个uni.scss,达到全局可用的效果。

我们在此只需要将skin.scss定义的css变量移动到uni.scss中定义即可,也无需在vite中声明。

scss 复制代码
$color-bg: var(--bg);
$color-theme: var(--mainColor);
$color-rgb-theme: var(--mainRgbColor);
$color-theme-d: var(--subColor);
$color-price: var(--priceColor);

3. 效果展示

4. 总结

最后总结一下,主要就是利用CSS变量和RGB转换,实现换肤效果,并且在书写中,优化了一点开发体验。

如有错误,请指正O^O!

相关推荐
夏幻灵39 分钟前
HTML5里最常用的十大标签
前端·html·html5
Mr Xu_1 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝1 小时前
RBAC前端架构-01:项目初始化
前端·架构
程序员agions1 小时前
2026年,微前端终于“死“了
前端·状态模式
万岳科技系统开发1 小时前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法
程序员猫哥_1 小时前
HTML 生成网页工具推荐:从手写代码到 AI 自动生成网页的进化路径
前端·人工智能·html
龙飞051 小时前
Systemd -systemctl - journalctl 速查表:服务管理 + 日志排障
linux·运维·前端·chrome·systemctl·journalctl
我爱加班、、1 小时前
Websocket能携带token过去后端吗
前端·后端·websocket
AAA阿giao1 小时前
从零拆解一个 React + TypeScript 的 TodoList:模块化、数据流与工程实践
前端·react.js·ui·typescript·前端框架
杨超越luckly1 小时前
HTML应用指南:利用GET请求获取中国500强企业名单,揭秘企业增长、分化与转型的新常态
前端·数据库·html·可视化·中国500强