vue2.x element-ui自定义主题 适配css var

2024-07-22  本文已影响0人  奋斗的小蜗牛yyl

B端业务中有个需求,不同的客户需要有自己的主题色, element-ui 官网提供的换肤方式不适用与用户自定义切换颜色(别问我为什么不升级,你懂得!),用户能切换的是内置好的,因为客户很多,不可能内置这么多主题。所以决定采用css变量来实现。说干就干~

1. 根据element-ui官网提供的方案(项目使用的是less,所以使用ele提供的主题工具)

第一步 安装主题工具和主题(推荐安装在当前项目下)


npm i element-theme element-theme-chalk -D


第二步 初始化变量文件

node_modules/.bin/et -i

执行后不出意外的话,意外出现了,报错了。。。开始手忙脚乱, 怀疑是不是姿势不对,再来一次还是报错


image.png

在网上冲浪了亿会会, 发现是node版本太高导致的 我使用的是14版本,建议是 11.15以下,解决方案有以下两种(冲浪的收获)

 - 安装低版本 node  11.15以下
 - 安装 element-themex

我这里用的是第二种方案 安装 element-themex

image-1.png

安装成功后再次执行 node_modules/.bin/et -i

image-2.png

这次终于成功了,开心~ !我们可以在根目录下看到 scss 变量文件

image-3.png

第三步 修改变量文件 这里把默认色修改为css 变量

image-4.png
/* Color
-------------------------- */
/// color|1|Brand Color|0
$--color-primary: var(--customize-theme) !default;
/// color|1|Background Color|4
$--color-white: #FFFFFF !default;
/// color|1|Background Color|4
$--color-black: #000000 !default;

第四步 执行编译主题命令(坐等主题生成 嗯哼!)


node_modules/.bin/et

天呐!意外再一次出现,报错了,天塌了!!!!

image-5.png

报错提示很明显,scss mix函数的入参需要是一个颜色值。我们传入一个 css 变量它是不支持的。因为ele主题中一些样式使用的是默认颜色与另外一种混合,根据一定的比例混合在一起,生成另一种颜色。于是网上冲浪~~无果!!!
没办法业务需求要实现,头发还是需要掉。
经过深思熟虑决定解决这个报错,手动改源码是不可能的,因为颜色是scss编译过程生成的,直接改源码的事就不想聊了~

2.修改 scss 变量的mix函数

第一步 实现 mixToVar 函数

其实ele提供的主题编译工具逻辑很简单,就是把 element-theme-chalk 中的变量暴露出来,供项目修改,修改后再执行编译命令,把修改后的主题文件重写进 element-theme-chalk 中的变量文件,在执行scss编译,把scss文件编译成css文件

那我们也可以加一层命令,就是把 mix 函数替换掉,替换逻辑很简单,读取element-theme-chalk中的scss文件,使用字符串替换就行,函数名为 mixToVar
mixToVar 入参与 mix 函数一致,这里不用去关心 mix 函数的内部实现
mixToVar 函数的需要实现的功能如下

mixToVar 具体实现如下 主要使用字符串相关的操作 判断索引、截取等

/* 自定义函数 */
@function mixToVar($c1, $c2, $percent: 50%) {

    $str: '';
    $len: str-index($percent + '', '%');
    $percentNew: $percent;

    @if $len {
        $percentNew: str-slice($percent+'', 0, $len - 1)
    }

    $c1Str: $c1+'';
    $c2Str: $c2+'';
    $c1VarIdx: str-index($c1Str, 'var(');
    $c2VarIdx: str-index($c2Str, 'var(');

    @if $c1VarIdx {
        $str: '#{str-slice($c1Str, str-index($c1Str, '(') + 1, str-index($c1Str, ')') - 1)}'
    }

    @else {
        $str: '--YS#{transformColor($c1)}'
    }

    @if $c2VarIdx {
        $c2Var: #{str-slice($c2Str,str-index($c2Str, '(') + 1, str-index($c2Str, ')') - 1)};
        $str: $str + '_#{$c2Var}_' + $percentNew;
        @return var(unquote($str));
    }

    @if $c1VarIdx {
        $str: $str + '_--YS#{transformColor($c2)}_' + $percentNew;
        @return var(unquote($str));
    }

    @return mix($c1, $c2, $percent);
}

@function transformColor($color) {
    $str: $color+'';
    $idx: str-index($str, '#');

    @if $idx {
        @return str-slice($str, $idx+ 1);
    }

    @return $color;
}

// YS 表示颜色值 后续容易分割字符串
// _ 后续分割字符使用

// mixToVar 返回示例

// 1
// mixToVar(#409EFF, var(--customize-theme), 60%)
// 返回结果 var(--YS409EFF_--customize-theme_60)

// 2
// mixToVar(var(--customize-theme), #409EFF, 60%)
// 返回结果 var(--customize-theme_--YS409EFF_60)

// 3
// mixToVar(var(--customize-theme), var(--customize-theme1), 60%)
// 返回结果 var(--customize-theme_--customize-theme1_60)

// 4
// mixToVar(#FFFFFF, #409EFF, 10%)
// 返回结果 #53a8ff

第二步 实现主题工具

函数已经写好了,后面就是替换mix函数, 为了和ele风格保持一致,我这里也简单实现一个命令行工具(需要一点node基础)ele-theme-tool,工具主要是转换 scss 文件
工具主要功能有下面几点:

因为变量是动态生成的变量,项目是无感的,项目不知道工具生成了那些变量,为了傻瓜式,主题工具生成好js方法

工具写好后发布,然后安装工具(项目使用less,scss都可以使用它生成element-ui主题)

npm i ele-theme-tool -D

安装成功后执行以下命令进行初始化


node_modules/.bin/ett -i

初始化完成如下图

image-7.png

我们可以打开 element-variables.scss看一下是否已经替换完成,且 mixToVar 函数是否注入

image-11.png

替换的文件会包含 node_modules/element-theme-chalk 里面的scss文件


image-8.png

再次修改element-variables.scss文件

/* Color
-------------------------- */
/// color|1|Brand Color|0
$--color-primary: var(--customize-theme) !default;
/// color|1|Background Color|4
$--color-white: #FFFFFF !default;
/// color|1|Background Color|4
$--color-black: #000000 !default;

第三步 执行element-ui提供的 主题编译方法 注意是 element-ui 提供的方法


node_modules/.bin/et

这一次没有出现意外,成功了!!!!!!!!!趾高气昂!!!!

image-9.png

打开生成的主题文件夹theme下的css文件可以看到,替换好的 css var函数

image-10.png

第四步 获取变量,并生产主题设置工具

虽然颜色值已经替换完成,但是可以发现都是一些颜色和变量组成的新变量,无法阅读,也没法在外面设置,所以工具的另外一个作用就是生成一个工具函数,供外部项目使用

执行ele-theme-tool 提供的命令


node_modules/.bin/ett -s

这个命令其实还有设置默认颜色(#409EFF)的功能,颜色设置没有暴露出来,有兴趣的自己实现下

执行完后可以看到css 文件已经修改

image-12.png

项目引入编译好的主题


import "../theme/index.css";

运行项目可以发现主题已经修改为默认的主题色 #409EFF

image-13.png

那如何动态修改呢?执行完命令后,项目根路径下多了一个 theme-tool-web.js 文件, 在项目中使用它

image-15.png

刷新页面可以看到,颜色值已经修改为设置的颜色

image-14.png

使用 ColorPicker 颜色选择器,直接切换颜色,也可以正常执行

image-16.png
如果使用中遇到问题可以初始化一个新的空项目,定义完主题后,把主题文件夹复制到实际项目中引用(element-ui 提供的自定义工具,其实就是生成了一个 css 目录)

ele-theme-tool 也可以直接通过js调用方式工作
例如根据element-ui二次封装的组件库可以使用此方式换肤, 这里就不在赘述,有需求,可以根据源码改造、封装

const { init, build, varUtil } = require('ele-theme-tool')

 init.themeInit({
    targetThemePathRoot,
    themeDir,
    themeVarName,
    themeVarPath,
    message: '初始化主题变量'
})

build.themeBuild({
    targetThemePathRoot,
    targetFontsRoot,
    themeDir,
    targetThemeVarPath,
    minimize: true,
    out: themeOutDir, 
    themeVarPath: path.resolve('variables.scss')
},() => {
    varUtil.setDefaultVarColor({
        themeDir:themeOutDir
    })
})

github地址: ele-theme-tool

总结:可以愉快的自定义主题了,如果需要兼容低版本浏览器,建议考虑其他方案或者使用css-vars-ponyfill适配

头发没了。。。,有更好的方案,可以再评论区分享下。

上一篇 下一篇

猜你喜欢

热点阅读