umi + antd 动态主题色

2021-05-29  本文已影响0人  林ze宏

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两个文件;

说明:为啥是 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 引入相关的文件路径即可。

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

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

1.5 开发步骤

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

1.6 总结

2 升级优化

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

umi + antd 动态主题色(二)

上一篇 下一篇

猜你喜欢

热点阅读