在以往的前端开发中,css 一直不能称之为一种编程语言,虽然在 css3中增加了几个变量和函数,但是实现的功能还是比较有限。后来出现了几个css预处理器,比较常用的有:sass、less 、stylus。有了他们,我们可以对css进行一些简单的编程。如果您对他们还不了解,可以查看一下他们的官网学习一下,vaw-layouts项目中使用的的预处理器是sass,因此本文也是基于sass进行讲解实现动态换肤的功能。
先说一下实现换肤的大体思路:
1、提前定义好几个不同命名空间下的class
2、通过js实现对元素动态切换class属性值
这种方式有几个缺点:
1、要提前定义好不同命名空间下的class,不够灵活
2、会增加打包后的应用体积
但是好在这种方式比较简单,适合大多数的场景。因此我们也采用了这种方式。
vaw-layouts中有四种不同的主题:light、dark、dark-side、blue-side
实际上主要的有两种:light dark。因为dark-side、blue-side两种主题只是对 sidebar和navbar进行了适配,主体内容并没有适配,因此我们主要说一下light和dark
其实如果我们不考虑dark的情况下,默认的就是light,我们可以把一个div设置成白色的背景,黑色的字体。这就是light主题了。所以light主题并不用多说什么,按照我们平常的开发该怎么写就怎么写。我们重点说一下怎么适配dark主题,正如前面说的,要实现动态换肤就可定义好不同的命名空间下的class,如下:
代码语言:javascript复制.dark{
.el-button {
background: $mainContentBgColor;
color: $mainTextColor;
}
.el-table {
background-color: $mainCardBgColor;
color: $mainTextColor;
.hover-row {
background-color: $mainCardBgColor !important;
}
th,
tr {
background-color: $mainCardBgColor !important;
}
th.is-leaf,
td {
border-bottom: 1px solid $mainTextColor;
}
}
div{
background: $mainContentBgColor;
color: $mainTextColor;
}
...
}
详解在 vaw-layouts 中通过 sass 实现动态换肤功能 (一)
原创2021-06-03 22:22·知码
在以往的前端开发中,css 一直不能称之为一种编程语言,虽然在 css3中增加了几个变量和函数,但是实现的功能还是比较有限。后来出现了几个css预处理器,比较常用的有:sass、less 、stylus。有了他们,我们可以对css进行一些简单的编程。如果您对他们还不了解,可以查看一下他们的官网学习一下,vaw-layouts项目中使用的的预处理器是sass,因此本文也是基于sass进行讲解实现动态换肤的功能。
先说一下实现换肤的大体思路:
- 提前定义好几个不同命名空间下的class
- 通过js实现对元素动态切换class属性值
这种方式有几个缺点:
- 要提前定义好不同命名空间下的class,不够灵活
- 会增加打包后的应用体积
但是好在这种方式比较简单,适合大多数的场景。因此我们也采用了这种方式。
vaw-layouts中有四种不同的主题:light、dark、dark-side、blue-side
实际上主要的有两种:light dark。因为dark-side、blue-side两种主题只是对 sidebar和navbar进行了适配,主体内容并没有适配,因此我们主要说一下light和dark
其实如果我们不考虑dark的情况下,默认的就是light,我们可以把一个div设置成白色的背景,黑色的字体。这就是light主题了。所以light主题并不用多说什么,按照我们平常的开发该怎么写就怎么写。我们重点说一下怎么适配dark主题,正如前面说的,要实现动态换肤就可定义好不同的命名空间下的class,如下:
代码语言:javascript复制.dark{
.el-button {
background: $mainContentBgColor;
color: $mainTextColor;
}
.el-table {
background-color: $mainCardBgColor;
color: $mainTextColor;
.hover-row {
background-color: $mainCardBgColor !important;
}
th,
tr {
background-color: $mainCardBgColor !important;
}
th.is-leaf,
td {
border-bottom: 1px solid $mainTextColor;
}
}
div{
background: $mainContentBgColor;
color: $mainTextColor;
}
...
}
这里只是简单说明一下,还有大量的css代码未列出。
说明一下:以 $开头的都是scss下定义的变量,如果不明白,还请查看官方文档。
1、$mainContentBgColor 主要指定背景色
2、$mainTextColor 主要指定文本颜色
同理,我们也定义好light下的class
代码语言:javascript复制.light{
.el-button {
background: $mainContentBgColor;
color: $mainTextColor;
}
.el-table {
background-color: $mainCardBgColor;
color: $mainTextColor;
.hover-row {
background-color: $mainCardBgColor !important;
}
th,
tr {
background-color: $mainCardBgColor !important;
}
th.is-leaf,
td {
border-bottom: 1px solid $mainTextColor;
}
}
div{
background: $mainContentBgColor;
color: $mainTextColor;
}
...
}
然后当我们需要切换背景色的时候就可以改变一下元素的class属性就好了,js代码如下:
代码语言:javascript复制export function toggleThemeClass(element, className) {
if (!element || !className) {
return
}
let classString = element.className
const clazz = classString.split(' ').filter(it => it.indexOf('theme_') !== -1)
clazz.push(className)
classString = clazz.join(' ')
element.className = classString
}
我们主要是把class应用到了body元素上
代码语言:javascript复制<body class="theme_color_blue light">
....
</body>
这样就可以完了动态换肤,你以为这就完了?肯定不是,这样有一个问题:
1、如果我们以后再定义几个主题,还得再写一遍上面的代码吗,大量冗余的代码,肯定不好
这个时候就体现出sass的强大了,我们知道,换肤就是改一下那几个变量的值:mainContentBgColor,mainTextColor。如果我们可以通过js动态地修改这几个值,不也可以实现动态换肤?答案是不可以,因为预处理器是在我们开发阶段使用,一旦打包之后,他们就没有了,我们也就没办法再改这些值。所以我们还是老老实实写恶心的代码?当然不行,虽然不可以动态改变这几些,但我们可以提前定义好不同命名下的变量,再通过scss生成不同的全名空间不就行了。如下代码:
代码语言:javascript复制// dark下的变量
@function getDarkMaps($primaryColor) {
@return (
dark-menuBgColor: #141414,
dark-contentBgColor: #0f0f10,
dark-activeTextColor: $primaryColor,
dark-textColor: #f5f5f5,
dark-menuActiveBgColor: #2f2f2f,
dark-badgeColor: #000000,
dark-headerBgColor: #141414,
dark-headerBorderColor: $primaryColor,
dark-headerTextColor: #ffffff,
dark-headerShadow: #7b7b7b,
dark-headerTabItemBgColor: #2f2f2f,
dark-headerTabItemActiveBgColor: #2f2f2f,
dark-headerTabItemTextColor: #f5f5f5,
dark-headerTabItemActiveTextColor: $primaryColor,
dark-mainBorderColor: $primaryColor,
dark-contentActiveBgColor: #2f2f2f,
dark-mainContentBgColor: #000000,
dark-mainCardBgColor: #141414,
dark-mainCardBorderColor: $primaryColor,
dark-mainTextColor: #f5f5f5,
dark-mainActiveTextColor: $primaryColor,
dark-popoverBgColor: #000,
dark-popoverBorderColor: $primaryColor,
dark-popoverTextColor: #f5f5f5
);
}
// light下的变量
@function getLightMaps($primaryColor) {
@return (
light-menuBgColor: #ffffff,
light-contentBgColor: #f7faff,
light-activeTextColor: #ffffff,
light-textColor: #333333,
light-menuActiveBgColor: $primaryColor,
light-badgeColor: $primaryColor,
light-headerBgColor: #ffffff,
light-headerTextColor: #333333,
light-headerBorderColor: #f5f5f5,
light-headerShadow: #f5f5f5f5,
light-headerTabItemBgColor: #e8f4ff,
light-headerTabItemActiveBgColor: #e8f4ff,
light-headerTabItemTextColor: rgb(97, 97, 97),
light-headerTabItemActiveTextColor: $primaryColor,
light-mainBorderColor: #ffffff,
light-contentActiveBgColor: $primaryColor,
light-mainContentBgColor: #f0f2f5,
light-mainCardBgColor: #ffffff,
light-mainCardBorderColor: #f5f5f5,
light-mainTextColor: #333333,
light-mainActiveTextColor: #888888,
light-popoverBgColor: #ffffff,
light-popoverBorderColor: #f5f5f5,
light-popoverTextColor: #333333
);
}
虽然这样也有冗余的代码,但比起一个个定义class 这样还算可以的
再通过 @each指令生成class
代码语言:javascript复制@mixin theme($themeName: 'light') {
@each $key, $value in $themeColorsMap {
// 这里就是生成类似于:.dark.theme_color_blue
// 因为我们还有切换主题色的功能,所以还得适配不同的颜色
.#{$themeName}.#{$key} {
@include mainLayout(
$mainContentBgColor: map-get($map: $value, $key: #{$themeName}-mainContentBgColor),
$mainCardBgColor: map-get($map: $value, $key: #{$themeName}-mainCardBgColor),
$mainCardBorderColor: map-get($map: $value, $key: #{$themeName}-mainBorderColor),
$mainTextColor: map-get($map: $value, $key: #{$themeName}-mainTextColor),
$mainActiveTextColor: map-get($map: $value, $key: #{$themeName}-mainActiveTextColor),
$parent: $themeName,
);
}
}
}
再看一下:mainLayout:
代码语言:javascript复制@mixin mainLayout(
$mainContentBgColor: $mainContentBgColor,
$mainCardBgColor: $mainCardBgColor,
$mainCardBorderColor: $mainCardBorderColor,
$mainTextColor: $mainTextColor,
$mainActiveTextColor: $mainActiveTextColor,
$parent: "light"
) {
.vaw-main-layout-container {
background-color: $mainContentBgColor;
color: $mainTextColor;
}
.footer-container {
background: $mainCardBgColor;
border-top: 1px dashed #848484;
color: $mainTextColor;
}
@if $parent == dark {
.el-button {
background: $mainContentBgColor;
color: $mainTextColor;
}
.el-table {
background-color: $mainCardBgColor;
color: $mainTextColor;
.hover-row {
background-color: $mainCardBgColor !important;
}
th,
tr {
background-color: $mainCardBgColor !important;
}
th.is-leaf,
td {
border-bottom: 1px solid $mainTextColor;
}
}
.el-table::before {
display: block;
}
.el-table__body tr:hover > td {
background-color: $mainContentBgColor !important;
}
.el-table__body tr.current-row > td {
background-color: $mainContentBgColor !important;
}
.el-table__body tr.hover-row > td {
background-color: $mainContentBgColor !important;
}
.el-message-box {
background-color: $mainCardBgColor;
.el-message-box__title {
color: $mainActiveTextColor;
}
.el-message-box__content {
color: $mainTextColor;
}
}
}
}
通过上面的代码我们就实现了:
代码语言:javascript复制.dark{
.xx1{}
.xx2{}
.xx3{}
}
这样的命名空间class,说了这么多就是为了生成这种样式的class。有点麻烦啊,但这样有一个好处是:我们以后再生成不同的主题就能生成 变量值就好了,不用写一个个class了。是不是很爽~~ 好了,文章太长了,但功能还没有完全实现,下一篇讲解如何实现动态换主题色。敬请期待~ 最后看一下效果图: