github: https://github.com/heyongsheng/hevue3-admin 码云: https://gitee.com/ihope_top/hevue3-admin 线上体验地址 https://ihope_top.gitee.io/hevue3-admin
本章主要知识点:
scss的安装、全局设置及一些常规用法 css变量的一些用法 element-plus自定义主题的两种实现方法 暗黑模式的视线
本文采用的是css变量和scss变量结合的方式,也不知道好不好,仅供大家参考吧。这里主要说一下在vite中如何使用scss。
vite提供了对 .scss
, .sass
, .less
, .styl
和 .stylus
文件的内置支持,我们只要安装相应的预处理器依赖就可以了,这里我们使用的是scss,所以要安装sass依赖
yarn add -D sass
之后我们就可以项目中愉快的使用scss了。
之后来讲一下如何在vite中配置scss全局变量。首先,我们可以在自己喜欢的目录创建我们的scss文件(通常是assets目录),用来存储颜色变量、尺寸变量,以及常用的mixin。
我们这里先在src/assets/style
下新建一个main.scss
,后期有其他变量再加
$themeColor : #9900ff;
如果我们在某个页面需要使用的话,直接在页面中引入即可,比如这样
@import '@/assets/style/main.scss';
但如果我们想要在每个页面中都可以使用,则需要在vite.config.ts
中进行配置
export default defineConfig({
// ...
css: {
preprocessorOptions: {
// 全局样式引入
scss: {
additionalData: `@use "./src/assets/style/main.scss" as *;`,
},
},
},
})
这里可以看到我们使用的是@use
而不是@import
,这是因为sass 团队说他们最终会删除 @import
语法。
之后我们就可以直接在页面中直接使用了。
<style lang="scss" scoped>
.test {
color: $themeColor;
}
</style>
这里的 as *
语法就是全部导入的意思,我们也可以把*
替换成我们想要的名字,比如改成globalScss。
export default defineConfig({
// ...
css: {
preprocessorOptions: {
// 全局样式引入
scss: {
additionalData: `@use "./src/assets/style/main.scss" as globalScss;`,
},
},
},
})
那我们使用的时候就需要加上这个前缀,这样也方便我们和局部变量做区分。
.test {
color: globalScss.$themeColor;
}
自定义主题主要分两种方式,第一种相当于是开发者自定义主题,也就是我们直接在代码中就写死一套或者几套颜色变量,想切换的时候就直接修改变量就行。第二种相当于是用户自定义主题,就是用户通过取色器选择一个颜色,之后我们把这个颜色设置为主题色。
本系统用的就是开发者自定义主题,就是提前写好颜色变量,因为都写好了,才发现的第二种,后期也会把第二种加入到系统里。其实两种方式不冲突,你可以既提前预置主题,又允许用户自定义主题。
先说第一种,开发者自定义主题,也就是我们直接在代码里写好颜色变量,然后适配element-plus就行。因为也没有看系统性的教程,我摸索好久才写出来的,可能不是最优方案,大家仅供参考吧
首先我们在src/assets/style/
新建一个theme.scss
,然后输入一些我们要设置的颜色变量
$light : () !default;
$light : ( // light theme
'--color-white': #ffffff,
'--color-black': #000000,
'--color-primary': #00ddff,
'--color-success': #67c23a,
'--color-warning': #e6a23c,
'--color-danger': #f56c6c,
'--color-error': #f56c6c,
'--color-info': #909399,
'--color-bg-1': #fff,
'--color-bg-2': #f5f5f5,
'--color-primary-reverse': #fff,
'--color-text-1': #000,
'--color-text-2': #333,
'--color-text-3': #666,
'--color-menu-bg': #fff,
'--color-menu-text': #7a7a7a,
'--color-border-1': #ddd);
在scss中,把变量放在括号里的格式叫做map,之所以使用map格式,是因为我们可以进行许多的操作,比如更方便的导入到其他文件,更方便的复用、遍历等(后面你就知道了)。$light是我们存储的默认状态下的主题,我们还需要把它输出的html里。
html {
@each $key,
$value in $light {
#{$key}: $value;
}
}
还记得我们之前的assets/style/main.scss
吗?我们在main.scss
中引入这个变量文件,就可以在页面中使用啦。
之后就是我们如何使用这些变量覆盖element-plus的默认样式。element-plus官网介绍了使用scss和css变量两种覆盖方式,这里我们介绍一下如何使用scss覆盖。
官方文档是这样写的
// styles/element/index.scss
/* 只需要重写你需要的即可 */
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$colors: (
'primary': (
'base': green,
),
),
);
首先我们需要在src/assets/style/element
里新建一个index.scss
,因为我们后续还要覆盖暗黑模式的变量,所以我们要在同级目录新建一个light.scss
用来覆盖默认样式。(这里不要把light.css里的内容整合到index里去,一定要分开写,不然可能会报错,我也不知道,都是试出来的)
@use 'sass:map';
@use '../theme.scss'as *;
@forward 'element-plus/theme-chalk/src/common/var.scss'with ( //
$colors: ( //
'white': map.get($light, --color-white),
'black': map.get($light, --color-black),
'primary': ( //
'base': map.get($light, --color-primary),
),
'success': ( //
'base': map.get($light, --color-success),
),
'warning': ( //
'base': map.get($light, --color-warning),
),
'danger': ( //
'base': map.get($light, --color-danger),
),
'error': ( //
'base': map.get($light, --color-error),
),
'info': ( //
'base': map.get($light, --color-info),
),
),
);
这里简单的说一下里面的scss技术点,@use 'sass:map';
就是引入map的操作方法,否则不能直接使用map的方法,map.get
就是获取map里的某个值,@forward with
就是往文件里传入参数,我们也可以理解为覆盖里面的某些变量
因为这是个开源项目,这里我把可以覆盖的主要颜色变量都给写上,在实际使用中,你只需要覆盖你想覆盖的那些变量即可,就像官方介绍的那样。
然后我们在src/assets/style/element/index.scss
中引入light.scss
// index.scss
@use './light.scss';
因为我们是按需引入的,所以不能再main.ts
用引入这个文件,还需要在vite.config.ts
中引入
export default defineConfig({
plugins: [
AutoImport({
resolvers: [
ElementPlusResolver({
importStyle: 'sass', // 增加此行
}),
],
}),
],
css: {
preprocessorOptions: {
// 全局样式引入
scss: {
additionalData: `
@use "./src/assets/style/main.scss" as globalScss;
@use "./src/assets/style/element/index.scss" as *;
`, // 在此处引入
},
},
},
})
我们随便修改一下theme.scss
里的变量,发现已经可以生效了
这一种我没有用在本系统中,但是在其他项目中尝试了一下,可以达到效果。这个方案也是借鉴的掘金上某大佬写的,vue3 admin 保姆教学指南|element-plus如何实现主题切换和暗黑模式,这篇文章内讲的比较详细,大家可以参考一下,本篇文章只介绍一下大概思路。
这是我的在线简历,里面用到了这个方案,点击右上角可以换主题色,大家可以体验一下,简历写的不好,大家不要笑话,如果有人有北京或上海的工作,也可以推荐一下。
element-plus的主要颜色就那么几种,其他的都是通过对这几种颜色的混合修改衍生出的或明亮或深色的衍生色。这个我们打开控制台就可以看到。
官网也列举到了用到的几个主题色
$colors: () !default;
$colors: map.deep-merge(
(
'white': #ffffff,
'black': #000000,
'primary': (
'base': #409eff,
),
'success': (
'base': #67c23a,
),
'warning': (
'base': #e6a23c,
),
'danger': (
'base': #f56c6c,
),
'error': (
'base': #f56c6c,
),
'info': (
'base': #909399,
),
),
$colors
);
之后通过对这几种颜色的加工(加工方式参考上面的文章链接),生成从深到浅的衍生色,然后输出到css变量。其实我们在项目中也可以直接使用这些css变量。例如
.word {
color: var(--el-color-primary)
}
我们需要做的就是用生成的变量覆盖掉element默认生成的这些css变量就行。我们都知道使用css变量,只需要用var()
包裹住变量名就行。如果我们想要在js中获取和设置css变量,则可以使用下面的方法
// 获取css变量
// 全局变量时el为document.documentElement
el.style.getPropertyValue(变量名)
// 或者
getComputedStyle(el).getPropertyValue(变量名)
// 设置css变量
el.style.setProperty(变量名, 变量值)
这里提一下css变量使用时注意的一个小点,css变量几乎可以在css的任意地方使用。但是无法在使用背景色时设置透明度,举个例子,我们设置背景透明色时基本都是这样
background: rgba(255, 255, 255, 0.5);
// 或者
background: rgba($color: #fff, $alpha: 0.5);
可以看到,rgba是支持传入16进制的颜色值的,但是我们如果使用css变量的话,会发现透明度并不能生效
--color-white: #fff
// 无效
background: rgba($color: var(--color-white), $alpha: 0.5)
解决办法我知道的有两种,一种就是背景单独搞一个dom,然后降低透明度,然后和内容重叠起来。
另一种就是使用scss变量。比如这种
html {
.page-content {
background: rgba($color: map.get(globalScss.$light, --color-bg-1), $alpha: 0.5);
}
}
html.dark {
.page-content {
background: rgba($color: map.get(globalScss.$dark, --color-bg-1), $alpha: 0.5);
}
}
还需要注意的一点就是,这种方式设置的css变量会直接显示在标签上,但也没什么影响
Element Plus的暗黑模式是通过html标签上是否存在dark类名判断的,我们可以手动的给html添加一个dark
类名,也可以用js动态的设置,不过官方最推荐的还是使用vueUse的useDark,使用方式如下。
import { useDark, useToggle } from '@vueuse/core'
// 暗黑主题切换
const isDark = useDark()
const toggleDark = useToggle(isDark)
我们切换暗黑模式,一般都会使用一个Switch组件,我们把isDark
赋值给Switch组件,在Switch组件change
时调用toggleDark
就可以了,useDark
会自动判断用户是否设置过暗黑模式,如果设置过,则按用户设置的展示,没设置过,则按自动模式,即白天默认,晚上暗黑。
这里简单说一下useDark
的切换逻辑,你白天的时候,将Switch组件切换到白天(也就是关闭状态),就是自动模式,切换到晚上,就是暗黑模式,此后会一直保持暗黑模式。你晚上的时候,将将Switch组件切换到晚上(也就是开启状态),就是自动模式,切换到白天就会是白天模式,此后会一直保持白天模式,简单的说就是你把状态手动的切换到与当前时间对应的模式,就是自动模式,你把状态切换到与当前时间相反的模式,就会是手动模式,此后会一直保持这个模式。
关于useDark的更多使用方法可以参考官网。useDark | VueUse
使用之后,我们就会发现它会自动的给html添加dark
类名,但是element的组件并没有切换到暗黑模式,这是因为我们还没有引入element-plus暗黑模式的样式。
如果你采用的是上面说的用户自定义主题,也就是通过js设置css变量的方式修改的主题,那么你直接按照官方的方式,在main.ts
引入一个css文件即可。
import 'element-plus/theme-chalk/dark/css-vars.css'
注意,使用用户自定义主题的方式的话,我们肯定要在页面初始化的时候设置一遍用户设置的样式变量,设置的时候需要用到nextTick
,否则可能会不生效(被element的暗黑模式样式覆盖了)。
如果你采用的是开发者自定义主题的方式,就是提前写好scss变量的那种,那需要按一下操作。(就算不是也建议阅读一下,可能学到那么一丁点的scss用法)
首先在theme.scss
中加入暗黑主题下我们需要用到的样式。
@use 'sass:map';
$light : () !default;
$light : ( // light theme
'--color-white': #ffffff,
'--color-black': #000000,
'--color-primary': #0471e6,
'--color-success': #67c23a,
'--color-warning': #e6a23c,
'--color-danger': #f56c6c,
'--color-error': #f56c6c,
'--color-info': #909399,
'--color-bg-1': #fff,
'--color-bg-2': #f5f5f5,
'--color-primary-reverse': #fff,
'--color-text-1': #000,
'--color-text-2': #333,
'--color-text-3': #666,
'--color-menu-bg': #fff,
'--color-menu-text': #7a7a7a,
'--color-border-1': #ddd);
$dark : () !default;
$dark : map.deep-merge($light, ( // dark theme
'--color-bg-1': #121212,
'--color-bg-2': #000000,
'--color-primary-reverse': #fff,
'--color-text-1': #fff,
'--color-text-2': #cfd3dc,
'--color-menu-bg': #121212,
'--color-menu-text': #7a7a7a,
'--color-border-1': #2e2e2e));
html {
@each $key,
$value in $light {
#{$key}: $value;
}
}
html.dark {
@each $key,
$value in $dark {
#{$key}: $value;
}
}
我们这里暗黑模式直接沿用默认状态下的变量,仅修改部分样式。之后,把暗黑模式的变量输出到html.dark
下。
这里我们说一下map.merge
,这个其实就相当于js中的Object.assign
,用于合并两个map,如果有相同的key,后面的会覆盖前面的,但不会影响原map,map.deep-merge
方法与map.merge
类似,但是如果value还是map,会递归合并。
之后就是实现element的暗黑模式了,我们需要在src/assets/style/element/
下面新建一个dark.scss
@use 'sass:map';
@use '../theme.scss'as *;
@forward 'element-plus/theme-chalk/src/dark/var.scss'with ( //
$colors: ( //
'white': map.get($dark, --color-white),
'black': map.get($dark, --color-black),
'primary': ( //
'base': map.get($dark, --color-primary),
),
'success': ( //
'base': map.get($dark, --color-success),
),
'warning': ( //
'base': map.get($dark, --color-warning),
),
'danger': ( //
'base': map.get($dark, --color-danger),
),
'error': ( //
'base': map.get($dark, --color-error),
),
'info': ( //
'base': map.get($dark, --color-info),
),
),
$bg-color: ( //
'page': #0a0a0a,
'': #141414,
'overlay': #1d1e1f,
));
@use "element-plus/theme-chalk/src/dark/css-vars.scss";
之后我们再在同目录的index.scss
引入
@use './light.scss';
@use './dark.scss';
到这里还没完,我们依然需要在vite.config.ts
中进行配置
AutoImport({
resolvers: [
ElementPlusResolver({
importStyle: 'sass',
}),
],
}),
Components({
resolvers: [
ElementPlusResolver({
importStyle: 'sass',
}),
],
}),
之后我们的自定义主题和暗黑模式就都可以使用啦
本篇文章就到这里了,下一篇会讲一下如何登录界面的一些注意事项、登录流程还有和后台管理中的权限管理