记录–前端换肤方案 – element+less无感换肤(无需页面刷新)

  • 记录–前端换肤方案 – element+less无感换肤(无需页面刷新)已关闭评论
  • 115 次浏览
  • A+
所属分类:Web前端
摘要

前不久在改造一个迭代了一年多的项目时,增加了一个换肤功能。通过自己的探索,总结出了一套比较合适的改造方案供大家参考,如有更好的方案欢迎评论区踊跃评论?


这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--前端换肤方案 - element+less无感换肤(无需页面刷新)

前端换肤方案 - element+less无感换肤(无需页面刷新)

前言

前不久在改造一个迭代了一年多的项目时,增加了一个换肤功能。通过自己的探索,总结出了一套比较合适的改造方案供大家参考,如有更好的方案欢迎评论区踊跃评论?

先上效果:

记录--前端换肤方案 - element+less无感换肤(无需页面刷新)

聊聊现有方案

在查阅现有方案时,总结了目前使用的几种方案:

1、定义多套样式

首先定义一套或多套样式变量,包括浅色和深色两种主题。在scss或less中使用变量,通过js改变root节点的class或属性来达到样式覆盖。 这种方式实现的前端换肤方案,可能会导致样式不易管理,查找样式复杂,每一套皮肤需要写一个css文件,造成多个css代码冗余。

$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文件,缺点是通过方法传入,当样式过多时,参数过多,需要改变某一个颜色成本高,容易造成问题。

.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快速切换黑暗和明亮模式。

<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变量

.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变量使用,解决了通过方法传参,参数过多的问题。

//换肤相关 @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,在最外层增加自定义的类。

.themeDark{     //下载的css文件     ... }

2、为了开发中不用每次去编译这个较大的less文件,再通过less命令,将less转为css

lessc + 空格 + less文件名

最终效果:

@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中

watch:{         '$store.state.myTheme'() {             this.getAllData();         } }

map

项目中使用到了腾讯地图,所以也需要更改在不同主题下不同的地图主题。在使用地图时我们知道,在引入地图时需要去引入地图的入口文件,入口文件中包含着需要加载的地图资源,所以我们只需要在腾讯地图官网定义不同的主题颜色,将其style.json保留下来,修改入口文件中的配置。

... 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的刷新。

/** * 切换肤色 */ 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); },

结语

以上便是本次换肤分享,由于该项目刚开发时并没有考虑到后续需要换肤的方案,在本次开发时也遇到很多细节问题,比如之前开发时主题色、各种状态颜色标准使用不一致,改造时我尽量去将一些相近的颜色做到统一,保持系统整体一致性。本次迭代也用了较短的时间实现了这个换肤功能,总体效率上来说这种方案和体验是比较好的。

本文转载于:

https://juejin.cn/post/7282290326068641847

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--前端换肤方案 - element+less无感换肤(无需页面刷新)