记录--前端换肤方案 - element+less无感换肤(无需页面刷新)
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
前端换肤方案 - element+less无感换肤(无需页面刷新)
前言
前不久在改造一个迭代了一年多的项目时,增加了一个换肤功能。通过自己的探索,总结出了一套比较合适的改造方案供大家参考,如有更好的方案欢迎评论区踊跃评论😄
先上效果:
聊聊现有方案
在查阅现有方案时,总结了目前使用的几种方案:
1、定义多套样式
首先定义一套或多套样式变量,包括浅色和深色两种主题。在scss或less中使用变量,通过js改变root节点的class或属性来达到样式覆盖。 这种方式实现的前端换肤方案,可能会导致样式不易管理,查找样式复杂,每一套皮肤需要写一个css文件,造成多个css代码冗余。
1 2 3 4 5 6 7 8 9 10 11 | $dark-fill-1: #222; $dark-color-text: #fff; $dark-color-text-1: rgba(255,255,255,0.3); $dark-color-text-2: $color-brand1; [data-theme= "dark" ] { body { background: $dark-fill-1; } .item .name { color: $dark-color-text; } .item .desc { color: $dark-color-text-1; } .header .text { color: $dark-color-text-2; } } |
2、使用less传参
通过less或scss的传参属性,同样的只要改变根节点class或属性即可以改变页面样式,与第一点的优点是不需要写多份css文件,缺点是通过方法传入,当样式过多时,参数过多,需要改变某一个颜色成本高,容易造成问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | .theme( @mainPageBG: #f4f6ff, @fColor: #1b1e29, @vanBgColor: rgb(198, 183, 140), @vanColor: #fff ) { .home { background: @mainPageBG; color: @fColor; } } .themeWhite { .theme(#fff, #1b1e29, rgb(198, 183, 140), #fff); } .themeBlack { .theme(#090c14, #fff, rgb(198, 183, 140), #fff); } |
3、VueUse+css变量快速切换
使用外部库VueUse的useDark快速切换黑暗和明亮模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <script setup lang= "ts" > import { useToggle } from '@vueuse/shared' import { isDark } from '../../.vitepress/theme/composables/dark' // const isDark = useDark() const toggleDark = useToggle(isDark) </script> <template> <button @click= "toggleDark()" > <i inline-block align-middle i= "dark:carbon-moon carbon-sun" /> <span class = "ml-2" >{{ isDark ? 'Dark' : 'Light' }}</span> </button> </template> |
最终解决方案
接触了解了上述几个方案后,结合项目本身架构(less+element+echarts+map),最终采用了以下使用方案。
less变量处理
1、定义不同肤色的css变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | .themeDark { --theme-color: #141414; --header-primary-color: #1a3750; --bg-content- default : #1a3750; --bg-theme- default : #13293b; --bg-left-color: #27415a; } .themeLight { --theme-color: #f4f4f4; --header-primary-color: #2670ff; --bg-content- default : #fff; --bg-theme- default : #f3f5f9; --bg-left-color: #eff3f4; } |
2、引入css变量,并通过定义less变量使用,解决了通过方法传参,参数过多的问题。
1 2 3 4 5 6 7 8 9 10 | //换肤相关 @import './dark.less' ; @import './light.less' ; @theme-color: var (--theme-color-te); @header-primary-color: var (--header-primary-color); @bg-content- default : var (--bg-content- default ); @bg-left-color: var (--bg-left-color); @bg-theme- default : var (--bg-theme- default ); @font- default -color: var (--font- default -color); |
element 主题切换
1、可以在element官网定制和下载不同主题的style文件,将css文件更名为less,在最外层增加自定义的类。
1 2 3 4 | .themeDark{ //下载的css文件 ... } |
2、为了开发中不用每次去编译这个较大的less文件,再通过less命令,将less转为css
1 | lessc + 空格 + less文件名 |
最终效果:
1 2 3 4 5 6 7 | @charset "UTF-8" ; .themeDark .fade- in -linear-enter-active, .themeDark .fade- in -linear-leave-active { -webkit-transition: opacity 0.2s linear; transition: opacity 0.2s linear; } ... |
3、main.js中引入
echarts
因为项目中使用了大量的echarts,在动态切换肤色时echarts需要重新加载才能改变,因此,需要通过监听全局变量,当改变皮肤时重新渲染echarts。将当前主题存放到vuex中
1 2 3 4 5 | watch:{ '$store.state.myTheme' () { this .getAllData(); } } |
map
项目中使用到了腾讯地图,所以也需要更改在不同主题下不同的地图主题。在使用地图时我们知道,在引入地图时需要去引入地图的入口文件,入口文件中包含着需要加载的地图资源,所以我们只需要在腾讯地图官网定义不同的主题颜色,将其style.json保留下来,修改入口文件中的配置。
1 2 3 4 | ... styleSrc: theme == 'themeDark' ? '/static/style.json' : 'https://xxxx/static/cdn/style{id}/style.json' , style3DSrc: theme == 'themeDark' ? '/static/style.json' : 'https://xxxx/static/cdn/style{id}/style.json' , ... |
js改变主题
做好以上准备工作,在main.js中在改变html的上的属性以及vuex来实现不用刷新更换不同主题。
将需要设置的主题存放到Storage中,以保证刷新后主题颜色不变,为了兼容UI框架(比如dialog会将dom渲染到body外),所以将class置于最顶层html上,改变主题的时候改变html上的class,这样下层所有的less变量将会使用该class下的颜色主题。修改vuex的值,用于触发echarts的刷新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * 切换肤色 */ changeColor(type) { this .themeClass = type; window.sessionStorage.setItem( 'themeClass' , this .themeClass); //动态修改html class,为了兼容UI框架,将class置于最顶层 const themeArr = [ 'themeDark' , 'themeLight' ]; let tempArr = document.querySelector( 'html' ).classList; tempArr.forEach((item) => { if (themeArr.includes(item)) { document.querySelector( 'html' ).classList.remove(item); } }); document.querySelector( 'html' ).classList.add( this .themeClass); //修改echarts的颜色 if (type == 'themeLight' ) { Vue.prototype.$themeChartColor = '#333' ; } else { Vue.prototype.$themeChartColor = '#fff' ; } //修改store的值,可用于触发相操作 this .$store.commit( 'setMyTheme' , type); }, |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2021-10-09 JQ实现音乐插件并自动播放