大家下午好。今天我们来介绍一种比较简单易实现的主题切换方案,接下来我将尽可能的把这种方案讲的清清楚楚明明白白。写的不好的地方也请大家伙见谅。
正文之前
近来,在项目上突遇主题切换的需求,一般来说是系统预设几套主题,如 浅|亮色(light)、暗色(dark)等等,其中还涉及到不同主题图片等的静态资源变更,以及echarts等的图表颜色变更。接下来本文将介绍较为简单的实现方案。
一: 主题切换方案
目前较为主流的主题切换方案主要有两种:
1. 方案一: css 变量切换主题(推荐)
- 优点:
- 简单,兼容性好,适合大部分项目,兼容绝大多数现代主流浏览器;
- 新增或修改主题方便灵活,仅需新增或修改CSS变量即可,在var()绑定样式变量的地方就会自动更换;
- 在需要切换主题的地方利用var()绑定变量即可,不存在优先级问题;
- 不用重新加载样式文件,在样式切换时不会有卡顿
- 缺点:
- 不兼容ie(但可忽略不计);
- 首屏加载时会牺牲一些时间加载样式资源
2. 方案二: 使用sass/scss、less等预处理器切换主题(推荐,本文暂不介绍)
- 优点:
- 不用重新加载样式文件,在样式切换时不会有卡顿;
- 在需要切换主题的地方利用mixin混合绑定变量即可,不存在优先级问题;
- 新增或修改主题方便灵活,仅需新增或修改SCSS变量即可,经过编译后会将所有主题全部编译出来
- 缺点: 首屏加载时会牺牲一些时间加载样式资源
3. 方案三: 使用传统方案切换主题,如 动态加载link,类名切换等(不推荐,本文不会介绍)
- 优点:
- 兼容性最佳;
- 实现了按需加载,提高了首屏加载时的性能
- 缺点:
- 代码量多,需提前写好几套样式代码,比较繁琐;
- 主题样式表内定义不当,会有优先级问题;
- 动态加载样式文件,如果文件过大网络情况不佳的情况下可能会有加载延迟,导致样式切换不流畅;
- 各个主题样式是写死的,后续针对某一主题样式表修改或者新增主题也很麻烦
实现效果
css变量实现
CSS变量实现过程
实现思路
- 定义预设主题并导入
- 定义全局主题变量
theme
- 在
html
根元素加入data-theme
自定义属性 - 使用
var(--bg-color)
取相对应的色值,如果需要js
动态取值变更,则使用getPropertyValue
API 取值赋值即可 - 动态绑定也可直接使用
var(--bg-color)
即可 - 静态资源通过
require
动态加载
1. 创建theme.css,定义预设变量
这里咱只定义了两套主题,浅色与暗系,大家有多套主题也是一样的。然后在 main.js
导入主题。
2. 创建 store
,定义全局变量 theme
定义全局变量且保存在本地缓存中(localStorage/cookie/sessionStorage
都可以),全局变量可以使用 vuex
, pinia
等,由于本文实现是使用 vue2.6.11
,所以在本文中采用 vuex
去定义操作。
3. 在 html
跟元素添加自定义属性
-
在
HelloWorld
组件中定义一个切换主题按钮,点击切换组件时触发vuex
变更主题的mutations
,随即更改主题并且给根元素定义data-theme
属性并赋值 -
根据
data-theme
属性的值辨别当前主题,结合咱第一步创建的预设主题变量,再使用var()
取主题变量就能完成初步主题切换的需求了 -
以
app.vue
为例,使用var()
实现切换
效果
可以看到,咱背景颜色,字体颜色已然完美实现了主题切换的需求。
4. 静态资源变更, js
取值赋值等
在上面已经完成了组件在 css
中切换主题色,但是切换的时候有时候需要把静态资源也同步更新,以图片为例:切换主题时,把 vue
的 logo 切换为 react
的 logo。
-
在
assets
文件夹下根据主题值新建文件夹,然后就可以根据theme
值的变化使用require
去变更静态资源 -
动态绑定
js
取主题值变更,一般应用在 echarts
图表类或者其他不能直接使用 var()
取切换的场景。
-
创建
echarts
柱状图 -
为了方便取值,本人在
utils
中定义了getPropertyValue
方法,getPropertyValue
API 作用是返回元素的css值,在前面使用getComputedStyle
为了拿到计算后最终的css
属性,与之对应的还有setProperty('background', 'red')
属性,作用是给元素设置新的css
属性值。 -
效果如下
-
这样就可以使用
getPropertyValue
配合echarts
实现切换主题了,还记得前面定义预设主题吗,我们定义了--charts-bar-bg
--charts-bar-color
两个变量。监听theme
的变化,从而改变echarts
的色值
完美
问题
按照以上步骤能实现主题切换,但是此时一刷新就会发现,页面会回归到默认的浅色主题,因为在页面刚加载时是没有 data-theme
属性的,因此我们得在页面加载的时候把 data-theme
加上。