前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小程序换肤

小程序换肤

作者头像
腾讯VTeam技术团队
发布2020-11-30 09:10:06
1.9K0
发布2020-11-30 09:10:06
举报
文章被收录于专栏:VTeam技术团队VTeam技术团队

导语 换肤,对于前端来说不算常见,却也肯定不陌生。但是大家有考虑过小程序端的换肤吗?今天我们就来聊一聊小程序的换肤。

前言

有这么一句老话说得好“人靠衣装佛靠金装”,应用的UI风格的重要性犹如一个人的装扮风格。一个应用经过UI设计师们的精心“打扮”同样能为App赚很高的“回头率”。

就像女人的衣柜里永远少一件衣服一样,一个应用可能也少一套皮肤,这里就涉及到换肤了。说起换肤,对于前端来说不算常见,却也肯定不陌生。所谓的换肤,无非就是颜色值的更换,在一般的前端项目中,实现的方法有很多种。但是大家有考虑过小程序端的换肤吗?!!

可以看看 Elementui 换肤 Demo:https://elementui.github.io/theme-preview/#/zh-CN。

换肤需求

一般来说换肤需求分两种:

  • 一种是静态换肤,提供几种可选择的颜色/主题样式,进行选择切换,一般可供选择的主题样式不会太多;
  • 另一种是动态换肤,可自定义色值,可通过取色板取色或者后端接口下发,可选择的范围比较大;

传统前端换肤方案

在聊小程序的换肤方案之前,我们大概看一下一般前端项目常见的换肤方案以及优缺点:

1、class 命名空间

这个应该是最简单的换肤方案,利用class 名称准备两个主题

代码语言:javascript
复制
.red-theme {    color: red}
.blue-theme {    color: blue}

根据所选皮肤,给标签添加对应的类:

代码语言:javascript
复制
<body class="red-theme">
    <p>红色主题 p>         ...body>
优缺点:
  • 优点:简单,好理解,好实现
  • 缺点:CSS中需多写主题的class,代码容易混乱;需手动编写

2. 生成多套CSS皮肤

利用CSS预处理语言(如:Less,stylus 或 sass)以及 Webpack、gulp等工具输出多套主题样式。

代码语言:javascript
复制
/** default-theme.css **/
.text { color: #333;}
/** red-theme.css **/
.text { color: red;}
/** blue-theme.css **/
.text { color: blue;}

页面加载后,根据用户需求通过js动态的link对应的皮肤样式。

代码语言:javascript
复制
// js动态处理 var theme = /\bt=(\w+)/.exec(location.search); theme = theme ? theme[1] : "light";
 changeTheme(theme);
function changeTheme(theme) {    var head = document.getElementsByTagName("head")[0];    var link = document.createElement("link");    link.dataset.type = "theme";    link.href = "assets/css/theme-" + theme + "/pages/home/home.css";    link.rel = "stylesheet";    link.type = "text/css";    head.appendChild(link);}

如果需要保存用户使用的主题,可以通过如下方式:

  • 利用路由标记
  • 利用cookie标记
  • 利用localstorage
  • 保存到后端服务器
优缺点:
  • 优点:简单,好理解,好实现
  • 缺点:需要手写两份以上CSS配色样式;切换样式需要下载CSS的时间

Tips: 动态加载CSS文件可能需求一定的等待时间,可根据HTML 的 rel 属性下的 alternate配合 link 的 disabled 实现一定优化。

3. CSS变量换肤

利用CSS变量设置颜色, 用js动态修改CSS变量,进而换色。如果不考虑兼容性,这是最佳换肤方案。

代码语言:javascript
复制
// variable.less:root {  --fill-1: #fff;  --text: #3c3c3c;  --text-1: #757575;  --text-2: #222;
  --font-size-large: 18px;  --font-size-large-x: 22px;  --font-size-medium: 14px;  --font-size-medium-x: 16px;  --font-size-small-s: 10px;  --font-size-small: 12px;}

在页面对css变量做引入使用:

代码语言:javascript
复制
// 页面使用@import "../../assets/less/variable.less";
.header {  position: relative;  height: 70px;  text-align: center;  font-size: 0;   .text {    display: inline-block;    vertical-align: top;    line-height: 70px;    font-size: var(--font-size-large);    color: var(--text-2);  }}

然后在页面中可以直接通过JavaScript修改变量的值

代码语言:javascript
复制
function changeColor(color = 'blue') { document.documentElement.style.setProperty("--theme-color",color);}
优缺点:
  • 优点:只需一套CSS文件;换肤不需要延迟等候;对浏览器性能要求低;可自动适配多种主题色;
  • 缺点:不支持IE, 2016年前的chrome,safari; 兼容性参见 Can I Use CSS Variables

4. Less 在线编译

使用 modifyVars()方法, 基于 less 在浏览器中的编译来实现。在引入less文件的时候需要通过link方式引入,然后基于less.js中的方法来进行修改less变量:

代码语言:javascript
复制
less.modifyVars({  '@themeColor': 'blue'});

link方式引入主题色文件:

代码语言:javascript
复制
<link rel="stylesheet/less" type="text/css" href="./src/less/public.less" />

小程序换肤方案

本文方案均以 less、gulp 为基本框架。

背景

在开发小程序的时候,尤其是开发第三方小程序,我们作为开发者,只需要开发一套模板即可,但是个别客户的小程序需要做定制化配色方案,也就是说,不同的小程序个体需要对页面的元素(比如:按钮,字体等)进行不同的配色设置。

方案以及问题

由于小程序它自身的技术特点,传统方案的 CSS变量以及 Less在线编译 换肤方案无法使用,所以小程序换肤方案主要是:

  1. 如果没有线上存在多套皮肤的需求,可以抽取颜色变量通过线下编译修改主题色。
  2. 如果有线上多套皮肤的需求,则采用传统前端的多套CSS皮肤方案加更改类名的方式。
  3. 针对动态换肤,后端接口返回色值字段,前端通过 内联 方式对页面元素进行色值设置。

这几种方案都有一些问题无法避免:

  • 方案1、2 比较死板,每次更改主题样式都需要发版小程序,如果主题样式变动不大,可以考虑这种;
  • 方案3 对于前端的改动非常的大,内联也就是通过 style 的方式内嵌到 wxml 代码中,代码的阅读性会变差,但是可以解决主题样式变动不用发版小程序的问题
方案一

针对方案一,我们只需要抽取相关的变量色值到独立的文件中,约定项目在使用色值的地方统一引用该文件的变量。当需要修改主题色的时候修改对应变量即可。

代码语言:javascript
复制
/** variable.less **/@theme-color: #FD7622;
@txt-default: #333;@txt-body: #666;@txt-info: #999;@txt-muted: #ccc;@txt-warning: #FF0500;@txt-highlight: @theme-color;@txt-link: #00a5e0;@txt-feeds: #314c83;@txt-white: #fff;

在编译阶段,通过 gulp-less的 modifyVars属性修改相关变量即可:

代码语言:javascript
复制
// gulpfile.jsvar gulp = require('gulp');var less = require('gulp-less');var rename = require('gulp-rename');
function lessTask() {  return gulp.src('./less/**/*.less')             .pipe(less({                  modifyVars: {      '@theme-color': '#757575',      '@txt-default': '#212121',     }       }))             .pipe(rename(function(path) {               path.extname = '.wxss'             }))             .pipe(gulp.dest('./wxss'))}
function autosTask() {  gulp.watch('./less/**/*.less', lessTask)}
exports.default = gulp.series(gulp.parallel(lessTask, autosTask))
方案二

这个方案我们需要定制多套主题变量,并编译出多套皮肤样式。

主题色变量配置文件

代码语言:javascript
复制
/** variable.less **/
#theme() {  .colors(dark) {    @theme-color: #000;  }    .colors(light) {    @theme-color: #fff;  }}

页面样式文件

代码语言:javascript
复制
@import 'variable.less'
.dark {  @colors: #theme.colors(dark);    .btn {      .btnMixin;  }}

.light {  @colors: #theme.colors(light);    .btn {    .btnMixin;  }}

.btnMixin() {  background: @colors[@theme-color];}

/** 输出 
.dark .btn {  background: #000;}.light .btn {  background: #fff;}
**/

页面中使用的方式

1.页面的 wxml 引入主题变量 theme

代码语言:javascript
复制
<view class="index-layout {{theme}}"> <button class="btn">按钮button>view>

2.通过页面中的 this.data.theme 来控制主题

代码语言:javascript
复制
page({  data: {    theme: ''  },
  themeChange(e) {    const { theme } = e.target.dataset    this.setData({ theme })  }})

上面两个方案到目前为止也只是解决了在less文件中的换色问题,而实际的项目中我们很多时候并不能避免一些色值是内联写在 wxml 上以及写死在 javascript 文件中的。

比如,下面的 radio 组件

代码语言:javascript
复制
<radio value="light" checked="true" color="#fd7622" />

这种情况下同样抽取出一个颜色变量的 wxs文件在 wxml 使用,如

代码语言:javascript
复制
// variable.wxsvar themeColor = {  dark: {    '@theme-color': '#333',  },  light: {    '@theme-color': '#fd7622',  },};

function getVariable(theme) {    return themeColor[theme]}
module.exports = getVariable;
代码语言:javascript
复制
<wxs src="@wxsVar" module="getVariable" />
<radio value="light" checked="true" color="{{getVariable(theme)['@theme-color']}}" />

js 文件同理,这里不再复诉。

方案三

小程序中要实现动态换肤,目前能想到的办法就是在涉及到颜色设置时通过 内联(设置 style 方式对页面元素进行色值设置。这种方法目前来说成本较高,对于已经成型的项目来说风险过大。

wxml设置颜色时我们同样可以通过 wxs来实现。

代码语言:javascript
复制
function getStyle(style, theme) {    return style + ':' + theme;}

function setStyle(styles = [], theme) {    if (!styles || !styles.length) return '';
    var styleArr = []    styles.forEach(function(style) {        styleArr.push(getStyle(style, theme))    })
    return styleArr.join(';');}
module.exports = setStyle;

wxml 中使用

代码语言:javascript
复制
<wxs src="@dynamic" module="setStyle" />
<view class="container">  <view class="box" style="{{ setStyle(['color', 'border-color'], theme) }}">    setStyle(['color', 'border-color'])  view>  <input type="text" placeholder="输入一个色值" style="{{ setStyle(['border-color'], theme) }}" bindconfirm="onChange"/>view>
代码语言:javascript
复制
Page({  data: {    theme: '#222',  },
  onChange(e:{detail: {value: string}}) {    this.setData({      theme: e.detail.value,    })  }})
示例

这里给一个简单的示例。

一个简单的Demo

最后

由于小程序的特殊性,在换肤这种需求中局限性还是很大的。以上只是给大家提供一下一些解决思路,如果大家有更好的方案的话欢迎留言。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯VTeam技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 换肤需求
  • 传统前端换肤方案
    • 1、class 命名空间
      • 优缺点:
    • 2. 生成多套CSS皮肤
      • 优缺点:
    • 3. CSS变量换肤
      • 优缺点:
    • 4. Less 在线编译
      • 小程序换肤方案
        • 背景
        • 方案以及问题
        • 方案一
        • 方案二
        • 方案三
        • 示例
      • 最后
      相关产品与服务
      云开发 CloudBase
      云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档