从零开始Vue3+Element Plus后台管理系统(17)——一键换肤的N种方案

news/2024/11/6 9:32:33/

暗黑模式

基于Element Plus和Tailwind CSS灵活的设计,我们很容易在项目中实现暗黑模式,具体可以参考之前的文章《从零开始写一个Vue3+Element Plus的后台管理系统(二)——Layout页面布局的实现》

换肤方案

如果需要给用户提供更多主题,更丰富的皮肤,就得自己来开发换肤功能了。

换肤的方式由易到难大概分为3种:

  1. 简单换肤,提供N种配色方案供用户选择,一般只对配色进行切换,比如禅道,它提供了蓝色、粉色、绿色等方案;
  2. 个性化定制,可以自己定制主要颜色、阴影、边框等样式,个性化更强;
  3. 整站模板,提供N个风格迥异的模版布局和UI界面,彻底改头换面。

技术实现

以下仅针对使用Element Plus 的项目中进行换肤。

CSS变量

在开始之前,需要先了解CSS变量,它是一个非常有用的功能,几乎所有浏览器都支持,除了IE。既然选择了Vue3,明摆着就不想支持IE,所以我们可以愉快的使用CSS变量。

Element Plus 提取并整理了所有的设计变量,并通过 CSS Vars 技术实现动态更新主题。在我们的项目中找到node_modules/element-plus/theme-chalk,查看其中的CSS文件,可以看到其中有各种组件用到的CSS变量的定义。我把index.css拿出来格式化并存档,方便日后参考使用。

格式化以后的文件有140多行,截取部分贴出来:

:root {--el-color-white: #ffffff;--el-color-black: #000000;--el-color-primary-rgb: 64, 158, 255;--el-color-success-rgb: 103, 194, 58;--el-color-warning-rgb: 230, 162, 60;...
}:root {color-scheme: light;--el-color-white: #ffffff;--el-color-black: #000000;--el-color-primary: #409eff;...
}

在f12控制台,或者查看单个组件的样式文件,可以看到Element Plus通过CSS变量来设置组件的样式。

image.png

image.png

继续研究Element Plus的包,可以找到这个文件node_modules/element-plus/theme-chalk/src/var.scss,它保存的是SCSS变量,最终生成了theme-chalk/index.css

如果只修改Element主题而不考虑动态换肤,我们可以通过修改SCSS变量定制自己的ep外观。但动态换肤就需要使用CSS变量来完成。

OK,讲了这么多,其实就是为使用CSS变量换肤做铺垫。

简单换肤的技术实现

项目开发过程中,在<style>中自定义样式,我会尽量使用EP的CSS变量,一是可以直接利用EP的dark模式,二是为将来换肤做准备。比如页面头部:

<style scoped lang="scss">
.v-header {...border-bottom: 1px solid var(--el-border-color);.logo {color: var(--el-color-primary);}
}
</style>

修改css变量

由此可以想到,在我们需要更换主题样式时,只需动态修改CSS变量即可。

// 修改 EP 主要颜色为 红色
document.documentElement.style.setProperty('--el-color-primary', 'red')

建立配色方案的CSS变量

当我们需要修改的变量数量很少时,一个个修改还好,属性多的话这种做法显然不够优雅。那么暗黑模式是如何实现一键切换样式的呢?

dark模式是通过在html标签增加.dark,同时新建了一份专属dark的CSS Vars。同理,只需给不同的主题设置不同的CSS Vars,然后动态修改html的class,就可以实现简单换肤。

document.getElementsByTagName('html')[0].className = theme

在assets/css中新建theme.css

.red {--el-color-primary: #ff2551;
}.pink {--el-color-primary: #f47983;
}.green {--el-color-primary: #0c8918;
}.brown {--el-color-primary: #ae7000;
}.grape {--el-color-primary: #725e82;
}

切换主题操作 ThemeSetting.vue,通过切换html的classname使用不同主题下的CSS Vars

const themes = [{ name: 'red', color: '#ff2551' },{ name: 'pink', color: '#f47983' },{ name: 'green', color: '#0c8918' },{ name: 'brown', color: '#ae7000' },{ name: 'grape', color: '#725e82' }
]function changeColor(theme: string) {document.getElementsByTagName('html')[0].className = theme
}

2.gif
到此为止,一个最简单的换肤功能已经出来了,后续可以在theme.css中增加更多的变量来实现更多样式的变化(变量名根据按照上面拿到的Element Plus的CSS变量即可),通过这个操作已经可以实现禅道系统的换肤功能需求。

主题持久化

还有一个小问题,那就是当我们刷新页面后,主题回到了页面最初的样子,看来又需要做状态的持久化喽,这已经是老生常谈了。照旧使用pinia加persist。

store/theme.ts

import { defineStore } from 'pinia'
import { ref } from 'vue'export const useThemeStore = defineStore('theme',() => {let scheme = ref('')// 设置配色主题function setScheme(str: string) {scheme.value = str}return { scheme, setCSS }},{persist: true}
)

修改换肤方法,把主题名称保存到状态管理中。

function changeColor(theme: string) {document.getElementsByTagName('html')[0].className = themeuseTheme.scheme = theme
}

layout下新建theme/index.ts 用于初始化主题,然后在main.ts调用

import { Pinia } from 'pinia'
import { useThemeStore } from '~/store/theme'export default (pinia: Pinia) => {const useTheme = useThemeStore(pinia)// const el = document.documentElementif (useTheme.scheme) {document.getElementsByTagName('html')[0].className = useTheme.scheme}
}

main.ts

// theme
import initTheme from '~/layout/theme'
initTheme(pinia)

OK,现在再刷新页面,也不会丢失主题状态了,打开控制台可以看到,我们选择主题已经保存在localStorage中,只有清除缓存,才会回到默认的主题。

image.png

写完最简单的方案,已经傍晚了,先休息一下吧。

方案二,个性化自定义

如果你用过Element UI,应该知道它提供了一个自定义主题功能,下载后即可使用。

方案二的思路和它类似,用户可以自己定义color,menu,border等一些常用值,然后保存为自己的主题方案

image.png

未完待续

项目地址

本项目GIT地址:https://github.com/lucidity99/mocha-vue3-system

如果有帮助,给个star ✨ 点个赞👍


http://www.ppmy.cn/news/166961.html

相关文章

30天从入门到精通TensorFlow1.x 第三天,tf.variable_scope()共享或重用变量

tf.variable_scope()共享或重用变量 文章目录 一、接前一天二、tf.variable_scope()共享或重用变量1. 背景2. 目的3. tf.variable_scope()基本参数3. tf.variable_scope()作用&#xff08;1&#xff09;.命名空间&#xff08;2&#xff09;.共享变量&#xff08;3&#xff09;.…

医院检验科检验系统(LIS)源码:临检、生化、免疫、微生物

一、检验科检验系统 &#xff08;LIS&#xff09;概述&#xff1a;对接HIS&#xff0c;医生工作站能够方便、及时的查阅患者检验报告。 二、检验科检验系统 &#xff08;LIS&#xff09;主要功能描述&#xff1a; 1.质控品管理&#xff1a; 医院设备质控&#xff08;编码、设…

QT非阻塞挂起

在Qt程序中&#xff0c;有时需要在一定时间内等待某个条件满足&#xff0c;但又不能使用阻塞的方式等待&#xff0c;否则会导致界面卡死&#xff0c;无法响应用户的其他操作。这种情况下可以使用Qt提供的非阻塞挂起方法&#xff0c;如下所示&#xff1a; void nonBlockingPaus…

Backtrader官方中文文档:第二部分Installation安装

本文档参考backtrader官方文档&#xff0c;是官方文档的完整中文翻译&#xff0c;可作为backtrader中文教程、backtrader中文参考手册、backtrader中文开发手册、backtrader入门资料使用。 Backtrader安装 安装须知 Backtrader是自包含的&#xff0c;没有外部依赖(除非你想使…

【Linux系统基础快速入门详解】Linux命令格式、特点、语法详解、选项、参数

Linux系统的命令行界面是Linux系统最常用的部分之一,通过命令行界面中的命令,可以进行文件操作、系统管理、网络管理等各种操作。本文将介绍Linux系统命令的格式、特点、语法、选项和参数等内容。 1. 命令格式 Linux系统命令的基本格式为: command [options] [arguments]…

时间序列——R语言基础

这里只提及到了R语言的最皮毛的应用&#xff0c;其实ts是重点提及的&#xff0c;因为他是专门为了时间序列设计的内置class&#xff0c;但ts还是太浅显了&#xff0c;故一定要看以下链接。 zoo的使用 xts的使用 以上链接涉及到了zoo与xts&#xff0c;也是时间序列分析时的重要工…

R语言-频数统计函数

R如何对数据进行分组 1. factor()函数 > mtcars$cyl <- factor(mtcars$cyl) > mtcars$cyl[1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4 Levels: 4 6 82. cut()函数 > cut(mtcars$mpg,c(seq(10,50,10)))[1] (20,30] (20,30] (20,30] (2…

R 语言 单位根检验

单位根检验是一种平稳性检验,零假设是有单位根,即不平稳;对立假设是平稳。经常使用增强的 Dickey-Fuller 检 验 (ADF 检验)。 fUnitRoots 包的 adfTest() 函数可以执行单位根 ADF 检验。tseries 包的 adf.test() 函数也可以执行单位根 ADF 检验。 注意,ADF 检验都是在拒绝 …