umi + antd 动态主题色

1 动态主题色

效果如下:

动态主题.gif

GitHub 源码:umi-antd-dynamic-theme 1.0.0 分支

1.1 前言

本人项目使用的 ui 库为 antd,样式为 less。

主题色的变化,antd 官网提供了相关的方案:定制主题,但是,该方案是静态的换肤,也就是已经知道系统需要什么样的主题色,根据相关的配置,antd 自动帮你做转化。

我接下来要讲的动态主题色变化,也就是,你的页面可能会有10种,或者20种颜色需要切换,你也不知道到底有多少种颜色,同时,文档也考虑到多人协助开发,开发人员只需要按照约定方式去编写样式、主题文件名、目录等命名规范,是本人真实项目应用总结。

主要思路:动态插入样式,覆盖系统已经编译好的相关样式,包括 UI 组件库 和 自定义样式。

1.2 实现

步骤一:在 Umi 里配置主题

如果你在使用 Umi,那么可以很方便地在项目根目录的 .umirc.tsconfig/config.ts 文件中 theme 字段进行主题配置。theme 可以配置为一个对象或文件路径。

"theme": {
  "primary-color": "#1DA57A",
},

或者 一个 js 文件

"theme": "./theme.js",

本人使用的是公司自己的框架,基于 Umi 进行二次封装,所以,在 本目录下的config/theme.ts 配置 @primary-color,就实现了默认主题色的配置。

步骤二:新建相关目录和文件

在根目录下,新建public目录,引入less.min.js,下载路径为:https://cdn.bootcss.com/less.js/2.5.3/less.min.js,同时新建 styles目录,再创建antd.theme.lesscomponents.less两个文件;

  • antd.theme.less:用来放置覆盖 antd UI 组件库样式;

  • components.less:引入项目各个开发人员的相关主题样式文件;

说明:为啥是 public 目录呢?因为 Umi 项目,public 目录下所有文件会被 copy 到输出路径,也就是相关的资源,是被直接放到项目根目录。

具体如下图:

public 目录

步骤三:Umi 配置 copy

copy 属性主要作用是,设置要复制到输出目录的文件或文件夹。其实原理就是利用 webpack 插件 copy-webpack-plugin ,只不过 Umi,抽成了配置,如下图:

说明:配置 copy 目的,就是将各个模块自定义主题样式,复制到 public styles 目录下,因为动态变化主题色时候,是需要覆盖掉相关的颜色。

步骤四:编写 Utils 方法

下面的方法主要是动态插入 less.min.js,动态插入自定义的相关样式,利用 less.modifyVars,传入相关动态主题色参数,改变自定义的相关样式。

根据如下代码,自定义的样式文件为/styles/components.less,该文件是作为统一的入口,引用 copy 到 public/styles 目录下的相关各个模块的样式 和 antd 样式;

自定义的变量有@header-bar-bg@primary-color

function _changeTheme(themeColor: string) {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  if (!(window as any).less) return;
  window.setTimeout(() => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (window as any).less.modifyVars({
      '@header-bar-bg': themeColor,
      '@primary-color': themeColor,
      // '@color-primary': themeColor,
    });
  }, 300);
}

let lessNodesAppended: boolean = false;

/**
 * 动态更改主题色
 * @param {string} themeColor 主题颜色
 */
export function onChangeTheme(themeColor: string) {
  if (!lessNodesAppended) {
    // 插入 less.js,和 颜色主题.less
    const lessConfigNode = document.createElement('script');
    const lessScriptNode = document.createElement('script');
    const lessStyleNode = document.createElement('link');
    lessStyleNode.setAttribute('rel', 'stylesheet/less');
    lessStyleNode.setAttribute('href', '/styles/components.less'); // public 目标下

    lessConfigNode.innerHTML = `
        window.less = {
          async: true,
          env: 'development',
          javascriptEnabled: true
        };
      `;
    lessScriptNode.src = '/less.min.js';
    lessScriptNode.async = true;
    lessScriptNode.onload = () => {
      _changeTheme(themeColor);
      lessScriptNode.onload = null;
    };
    document.body.appendChild(lessStyleNode);
    document.body.appendChild(lessConfigNode);
    document.body.appendChild(lessScriptNode);
    lessNodesAppended = true;
  } else {
    _changeTheme(themeColor);
  }
}

1.3 页面组件样式编写

经过以上步骤,就已经大功告成了,接下来就可以开心编写组件和相关的自定义样式了。

约定,相关的主题颜色需要抽成 xxx.theme.less,然后,在组件引入该文件,如编写 List 组件,List.less 样式文件引入 List.theme.less,如下图:

less 样式需要使用 prefix,不能使用 import styles from './Less.less' 这种写法,因为如果使用该写法,则样式编译会被加上 hash,动态主题色覆盖就无法覆盖了。antd 官网组件也是使用 prefix 样式写法。

接下来只需要在 config/path.config.tspublic/styles/components.less 引入相关的文件路径即可。

  • config/path.config.ts 配置组件的 List.theme.less 主题色;

  • public/styles/components.less 新增 “config/path.config.ts” 配置的目标主题色路径;

1.4 解决覆盖 antd UI 库组件样式

public/styles/antd.theme.less 文件引入所有 antd 组件样式(谷歌吧),然后在public/styles/components.less @import 该文件。

1.5 开发步骤

如果按照文档上面的配置,那么整个系统动态主题色就配置好了,接下来就是按照约定规范,所有的开发人员,在编写页面或者组件,只需要配置如下两个地方既可,同时,注意所有的颜色都使用变量。

  • config/path.config.ts 配置组件的 xxx.theme.less 主题色;

  • public/styles/components.less 新增 “config/path.config.ts” 配置的目标主题色路径;

1.6 总结

  • theme.ts 定义主色调'@primary-color': '#5176EA',、辅助色等相关颜色'@color-secondary': '#6c757d'

  • 如果有额外的不同颜色,那就需要重新定义对应的变量;

  • 所有页面的主题色、辅助色,都使用变量 @primary-color、@color-secondary

  • 相关的主题色、辅助色样式,都需要单独抽出来;

  • 每个页面模块或者组件,都需要先新建对应的主题样式文件,规范为 xxx.theme.less;

  • 为了解决 less 模块化问题,项目统一使用 classPrefix 方案;

  • 所有页面和组件样式定义的变量,前缀命名需要按照一定的规范,组件前端是 c-文件名称,页面路由 p-文件名称

  • 如果页面覆盖 antd 样式,需要加 !important,或者在 xxx.theme.less 中编写;

2 升级优化

主要是对一些问题的优化升级,方便开发人员。

umi + antd 动态主题色(二)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容