前端主题色切换的终极解决方案

Hello大家好,我是日拱一卒的不浪,坚持从工作和生活中不断学习,提炼,沉淀,最终建立自己的强势领域!这是2024年输出的第6/100篇文章,欢迎志同道合的朋友一起学习交流;

公众号:攻城师不浪
绿泡泡:brown_7778

需求背景

最近在工作当中遇到一个需求,做一个后台管理系统,但是我们只做内容区,头部导航以及左侧菜单栏都不需要我们做,最后页面需要嵌套进兄弟部门的系统中,最终我们选择的用iframe的方案进行嵌套。

这时候需求就很明确了,因为切换主题的按钮在头部导航栏中,所以说我们是没法直接控制这个按钮的,只能通过iframe的src进行传参,然后我们根据这个参数去判断该用哪个主题色。

需求分析

看了网上比较火的几个方案介绍

https://juejin.cn/post/7134594122391748615

这里边介绍的大多是利用css的变量去解决,对我有一定的启发,但是我的需求里还需要在js中切换主题色,就比如echarts图表里的tooltip,也是要根据主题色进行变换的。

 tooltip: {
    textStyle: {
      color: #fff // 如果是黑色主题,就需要浅灰色了
    },
    backgroundColor: #fff,
 }

用过echarts的都知道这个配置是在js里进行的,那我要怎么才能在js里统一获取到主题色的变量呢?

js中使用css变量

我猜,一定还有部分同学不知道如何在js中使用css变量,其实我也是最近才学会的技巧。

创建主题文件

这里我们结合我的项目使用less举例,css也是同样的道理。首先新建src/style/light.module.less,注意了,文件类型是module.less

// 亮色主题
@color-primary: #0a8cfa;
:export {
  --color-primary: @color-primary;
}

全局引用

定义了less变量,我想要在项目的任何地方都能直接使用,以vite编译工具为例,在vite.config.js里配置

export default defineConfig({
  //...
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true, // 允许在Less中使用js语法
        additionalData: `
          @import "${path.resolve(__dirname, 'src/style/light.module.less')}";
        `
      }
    }
  }
  //...
})

配置之后,就可以在项目的任何一个页面使用less变量

// less代码
.box {
  color: @color-primary;
}

js中使用

还是结合项目,我使用的vue3,所以在script标签中使用

<script setup>
import cssVar from '@/style/light.module.less'

const primaryColor = cssVar['--color-primary'] // 输出#0a8cfa
</script>

感兴趣的同学可以尝试打印一下cssVar,它是一个对象,会把light.module.less里的:export内容以一个对象的形式全部输出。

主题色切换

创建暗色主题

我们已经创建了一个light.module.less了,接下来再创建一个暗色系:dark.module.less

// 暗色主题
@color-primary: #000;
:export {
  --color-primary: @color-primary;
}

保持变量名一致,只是不同。

主题色文件按需加载

通过路由拿到主题参数参数dark,例如

xxx?theme=dark

然后在router.beforeEach全局前置守卫钩子处进行判断,定义route文件,例如/src/route/route.js

import { createRouter, createWebHashHistory } from 'vue-router'
import { createPinia } from 'pinia'
import { useGlobalStore } from '@/store/global'

const routes = [
  //...
]
// 创建路由
export const router = createRouter({
  // hash 模式。
  history: createWebHashHistory(),
  routes
})
export const pinia = createPinia()

// 设置html标签的style属性,将所有的主题色变量都添加到行内样式
const setStyle = (styles) => {
  if (styles) {
    for (let key in styles) {
      document.getElementsByTagName('html')[0].style.setProperty(`${key}`, styles[key])
    }
  }
}
// 全局前置守卫,进每个页面前都会触发该钩子
router.beforeEach(async (to, from, next) => {
  const { theme } = to.query
  const globalStore = useGlobalStore()
  // 根据路由参数判断需要加载的主题色文件
  await import(`@/style/${theme}.module.less`).then((module) => {
    // module.default就是主题色文件导出的所有颜色变量
    if (module.default) {
      // pinia创建的全局状态
      globalStore.setTheme(module.default, theme)
      setStyle(module.default)
    }
    next()
  })
})

export default routes

setStyle做的事情就是将所需的变量都塞进html的style标签里,如下:

塞进之后,我们就能够在css里直接使用主题色变量了

.box {
  background: var(--color-primary)
}

也可以直接在html标签中使用:

<div style="color: var(--color-primary)">测试模板使用</div>

再看下useGlobalStore做的事情,当路由参数发生变化时,及时切换全局状态,创建/src/store/global.js

import { defineStore } from 'pinia'

export const useGlobalStore = defineStore('global', {
  state: () => {
    return {
      theme: {}, // 主题色配置
      themeName: 'light' // 主题色名称
    }
  },
  actions: {
    // 当路由参数发生变化时,及时切换全局状态
    setTheme(theme, themeName) {
      this.theme = theme
      this.themeName = themeName
    }
  }
})

js获取切换后的主题色变量

在js中,通过全局store获取更新后的主题色变量

<script setup>
import { useGlobalStore } from '@/store/global'
const globalStore = useGlobalStore()
// 更新后的主题色,获取的是一个对象
const theme = globalStore.theme
</script>

echarts的主题色不更新

如果项目中用到echarts,并且tooltip也会随着主题色变换而更新,此时你会发现颜色并没有随着全局store的theme的变化而更新,如下:

const chartOption = ref({})
const drawRateChart = () => {
  chartOption.value = {
    title: [
     //...
    ],
    tooltip: {
      trigger: 'item',
      textStyle: {
        color: globalStore.theme['--color-primary']
      },
      backgroundColor: globalStore.theme['--color-primary']
    },
    //...
  }
}

目前我的做法是监听全局store的themeName,当它发生改变时,重新执行一遍chartOption的赋值

watch(
  () => globalStore.themeName,
  (newVal, oldVal) => {
    if (newVal !== oldVal) {
      drawRateChart()
    }
  }
)

如果有更好的方案,欢迎评论区交流。

总结

  1. 利用module.less可以导出变量的能力;
  2. 利用路由全局前置守卫beforeEach按需加载主题色文件;
  3. 根据路由参数更新html标签的行内主题色变量;
  4. 利用状态管理在js中获取更新后的主题色变量;
  5. echarts如何更换主题色;

好了,以上就是根据最近的奇葩业务需求,我所给出的方案,如果有更加优雅的方案,欢迎和我(brown_7778)探讨~

如果在成长的路上感到孤单,可以交个朋友:brown_7778,围观我的朋友圈,每天输出技术、科技、认知与感悟,让我们携手并进。

如果觉得文章对你有帮助,欢迎点赞``关注``转发,你的鼓励是支持我持续原创下去的动力~

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1、设计的目的 做个网站以纪念港珠澳大桥彰显大国基建魅力,为中国工程师点赞喝彩。港珠澳大桥此刻的美丽,以及无限的未来向往正是中国工匠人的工匠精神延续。 2、设计布局 主页设计布局是在网站的左上角是网站标题名称为港珠澳大桥、首页、项目简介、设计理念、设计特点、大桥影响、桥见美景共六大模块,点击相应的导航栏目页面跳转到相应位置。首页采用div+js+css来实现四张港珠澳大桥背景图的引入和隔一定时间实现循环自动来回切换背景图,通过js设置切换间隔,每张图的停留时间。网站中央是内容,分别包含五大板块,每个版块由不同的div块组成,右上角是主题,下面是详情的文字介绍,右边配上相应的图片,增加网站的观赏性,吸引性。港珠澳大桥美的恰恰是其在不同场景下的景图。网站底部分别是网站版权介绍信息,采用居中透明显示,文字大小和样式用css来控制,美观大方。 3、网站具体设计过程 首先选定 本网页制作工具是前端开发利器: WebStorm,创建前端项目工程,并创建相应的文件夹,存放各个css、js,还有网页中用到的各种图片,以及除了主页面index.html之外的二级页面,其存放在html文件夹下,在各个二级页面与主页跳转的网页链接上采用相对路径而不是绝对路径,创建好的项目工程目录结构如下所示: 站点结构图: 首先设计网站主页也就是核心内容index.html。页面总体采用 CSS+DIV 布局,最外层DIV为框架。导航栏主要采用a标签以及span标签,并在a标签里面用锚点链接到其对应的模块位置,点击即可跳转到指定位置,使得网站更加人性化,方便展示内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值