实现主题切换有两种主流的解决办法,使用 CSS 变量或者使用预编译器。考虑浏览器兼容性,所以选预编译器方式实现。
主题切换的原理很简单,在 html 标签上添加 data-theme
属性,根据不同的值匹配不同的样式。
例如我这里以 SASS 实现 data-theme="light"
和 data-theme="dark"
两种主题为例,需要先掌握 SASS 的 @mixin、@each、@content、@function、map-get、@include 等用法。
定义不同主题下的颜色变量
$themes: (
light: (
bgColor: #fff,
textColor: #000
),
dark: (
bgColor: #000,
textColor: #fff
)
);
使用 mixin 自动生成不同主题
@mixin useTheme() {
@each $key, $value in $themes {
$curTheme: $key !global;
html[data-theme='#{$key}'] & {
@content;
}
}
}
$curTheme: light
定义当前主题,默认是 light- 使用
@each
遍历$themes
变量,自动生成不同主题 $key
代表 light 或者 dark,$value
代表各自后面的对象$curTheme: $key !global;
代表在每次循环种,将$key
赋值给全局变量$curTheme
,全局变量在后面会用到- & 代表使用
@include useTheme
的选择器 @content
代表@include useTheme()
括号内传递的内容
使用方式
.item {
width: 100px;
height: 100px;
@include useTheme {
background: #fff;
color: #000;
}
}
至此,上面的写法会生成如下的 css 代码:
.item {
width: 100px;
height: 100px;
}
html[data-theme='light'] .item {
background: #fff;
color: #000;
}
html[data-theme='dark'] .item {
background: #fff;
color: #000;
}
可以注意到 light 和 dark 的样式是一样的,因此 item 里面的值不能写死,我们要找到一种机制能够方便的读到对应主题的相应变量。我们可以定义一个函数 getVar,传入 key 读取当前主题下的变量值:
使用方式
.item {
width: 100px;
height: 100px;
@include useTheme {
background: getVar('bgColor');
color: getVar('textColor');
}
}
函数 getVar 实现
@function getVar($key) {
// 先取对应主题的变量对象
$themeValue: map-get($themes, $curTheme); // 再取变量对象里面的值
@return map-get($themeValue, $key);
}
map-get
就是取对象的属性- 其实在 useTheme 里面可以直接
$curThemeValue: $value !global;
,那么这里 getVar 可以简写成@return map-get($curThemeValue, $key)
至此,上面的写法会生成如下的 css 代码:
.item {
width: 100px;
height: 100px;
}
html[data-theme='light'] .item {
background: #fff;
color: #000;
}
html[data-theme='dark'] .item {
background: #000;
color: #fff;
}
最后我们调整下目录结构,将变量单独提取一个文件,将方法提取另一个文件,我们只需要维护变量文件,编写时引入方法文件使用 useTheme 即可。