如何修改和扩展element plus的样式

7,590 阅读5分钟

一、用户故事

我们组有多个团队多个项目,遵循同一规范,虽然有很多高度重叠的模块,但是各自为战,重复造了很多一个的轮子。所以这时候就是业务组件库来解决这一问题。

我们组遵循的设计规范理论上是要依托于另外一个部门的UI组件库。这个UI组件库基于element ui之上,进行了主题的修改和样式的扩展的,实现的方式是直接修改的源码。

而问题就出在这里。我们组的项目都升级为vue3版本了。所以公共部分的UI组件库自然无法使用。

在沟通过后,知晓他们升级的vue3的版本是elment plus。且实在等不及它们版本的升级,所以我们决定自己弄一套主题临时过渡。

二、需求分析

在确定了我们的需求之后,从需求中拆解出重点。

  • 主题包括主题色和样式的扩展
  • 临时

基于以上两点,我们可以得出下面的分析。我有如下三种实现方案:

直接对样式进行覆盖

比如说button的样式是el-button来控制的。只要知道他们的类名,就可以直接通过类名来进行样式的覆盖。但是这样会有一个问题,我们的前端使用的是qiankun框架。qiankun字段的样式隔离模式就是一个坑。所以我们都是通过命名空间来隔离的。

如果我们直接对样式进行覆盖的话,el这个前缀如何让用户传进来是一个问题。除此之外,怎么才能能什么classname控制什么样式呢?阅读源码还是打开element plus官网看着控制台?

这样的方式费力费劲。

弃之。

直接将element plus上面的 theme-chelk 项目拷贝下来,对源码进行修改

这个方案实现的起来比较简单,但是是在我做完之后才体会到这方案的好。一开始还是太年轻了。

当时排除的原因就是觉得这样要弄清楚element plus主题项目的代码,才可以下手,毕竟是临时用的,觉得会花很多的时间。

没想到的是,我后面选择的这个方案也需要看完源码。。。

很遗憾的弃之。

使用 scss 的特性对element的样式进行覆写

这个方案的在我草草看了官网就定下来的,感觉很简单。唯一的需要的就是对 scss 比较全面的了解。也是因为这个原因,实现的时候掉入了不少的坑。

三、需求实现

遗憾的选择了第三种方案,那么就要解决相应的问题。由于我们的业务组件库和业务项目都是依托于element plus的,所以业务组件库是不将element plus打包进项目当中的。

综上所述,我们需要做如下的工作:

3.1 获取自定义命名空间

由于我们的项目是通过自定义命名空间来解决样式隔离的问题的。所以说我们需要一个入口,让用户在使用我们的业务组件库的时候传进他们的自定义命名。

一开始我走了弯路,在查找js如何将变量传入scss当中。搜索了半天没有任何结果。就在想要通过插件来实现的时候。突然发现了一个很简单的方法:

用户在使用我们的主题的时候,需要单独创建一个scss文件:

@forward '@bbb/design-theme/src/index.scss' with (
  $bbbNamespace: 'yarn'
);

也就是通过scss覆写的方式将@bbbNamespace这个变量传进来。然后我们在@bbb/design-theme/src/index.scss中接受:

$bbbNamespace: 'el' !default;

@forward 'element-plus/theme-chalk/src/mixins/config.scss' with (
  $namespace: $bbbNamespace
);

就这。就这。

我想了一天。源于一直以来对于scss这种的排斥,我从来没有去学过。用到的时候才知道痛。

3.2 主题色的改变

官网已经很明确了。主题 | Element Plus (gitee.io)

使用scss的minxin和@forward搭配来对样式进行重写。

前提是我们需要知道什么是主题色。我们可以通过控制台的Elements的Styles来直接查看:

image.png

随后直接:root {} 覆盖即可。

3.3 组件样式的扩展

我们以扩展button的类型的为例子。默认的buttonsize类型有large | mudium | default 三种类型。现在我们想要给它添加一个bbb类型。

打开 element-plus/theme-chalk/src/button.scss 文件,可以看到控制button的size如下:

image.png

知道了控制button的size值是由@button-padding-vertical@button-padding-horizontal@button-border-width@button-font-vsize@button-border-radius这五个变量来定义的。

打开element-plus/theme-chalk/src/common/var.scss 文件,可以看到这五个变量的定义,我们就需要再index.scss中覆写他们,如下:

@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  $button-padding-horizontal: (
    'large': 24px,
    'bbb': 16px
  ),
  $button-padding-vertical: (
    'large': 10px,
    'bbb': 6px
  ),
  $button-font-size: (
    'bbb': 12px
  )
)

但是我们没有办法直接给上图中的@each @size in (large, small)。。。添加一个bbb。也就是说这个时候直接变量,而没有对应的大小class name。

对于这个问题,我的解决方法就比较直接,直接在index.scss中写一个出来,如下:

@use 'element-plus/theme-chalk/src/common/var' as *;

.#{$gasNamespace}-button--mini {
  padding: (map.get($button-padding-vertical, 'mini') - $button-border-width)
    (map.get($button-padding-horizontal, 'mini') - $button-border-width);
  font-size: map.get($button-font-size, 'mini');
  border-radius: map.get($button-padding-vertical, 'small');

  &.is-round {
    padding: (map.get($button-padding-vertical, 'mini') - $button-border-width)
      (map.get($button-padding-horizontal, 'mini') - $button-border-width);
  }
}

值得注意的是,上面我们只是对于element-plus/theme-chalk/src/common/var.scss的重写。所以我们在下面想要使用它的话,还需要单独的引用才可以。

至此,给button组件的size属性添加一个bbb类型的方式就实现了。

如果有更好的方法,求求大家发给我。

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情