BuildAdmin18:网站一键切换暗黑模式,到底是如何实现的

2024-09-10 07:58:56 浏览数 (1)

前言

之前的菜单栏想按照BuildAdmin的模式,来实现一个 Terminal 终端。

我以为是和CRT这样交互式终端,结果是类似于预编辑的命令脚本,然后在远程服务器上执行,和预想的结果不太一样。如果想要实现我的预想效果,还要涉及websocket。

其实到这里也还好,只不过后来的terminal库没有研究明白,所以就直接将 terminal 的图标,直接换成了暗黑模式切换图标,借此实现了BuildAdmin暗黑模式和正常模式的切换。

切换按钮

首先设计暗黑模式的切换按钮,我直接使用的 Element Plus 的 el-switch 开关组件。我想在亮光模式下图标是个小太阳,暗黑模式下是月亮,所以需要用到自定义图标的功能,直接复制 Element Plus 官网给出的代码。

在这里我踩了一个坑自定义图标这个功能需要 Element Plus 最低版本是2.4.4,当时我没看到tag提示,就一直没有显示图标,后来排查了很久才发现我使用的是2.2.1版本,后来升级了最新版本才能正常显示图标。

查看 Element Plus 版本和升级的指令如下:

代码语言:shell复制
npm show element-plus version
npm install element-plus@latest

开关图标

去图标网站下载 moon 和 light 的 svg 图标,当然也可以使用 Element Plus 的图标,使用方法在官网有说明。这里我下载的 svg,然后分别在 active-actioninactive-action 插槽中,插入自定义的 Icon 图标。

代码语言:html复制
<template>
    <el-switch v-model="is_switch" size="small"
               style="--el-switch-on-color: #2C2C2C; --el-switch-off-color: #CFD3DC"
               >
        <template #active-action>
            <Icon name="local-moon" size="12" />
        </template>
        <template #inactive-action> 
            <Icon name="local-light" size="12" />
        </template>
    </el-switch>
</template>

在 el-switch 组件中绑定 is_switch 响应式变量,然后在开关切换时会自动修改这个变量。

代码语言:JavaScript复制
<script setup lang="ts">
    import { ref } from 'vue'
    const is_switch = ref(false)
</script>

这里要注意的是,is_switch 要设置为false,这样在开关初始位置才能在左侧。然后官网代码中的图标样式过大,所以将 size 属性设置为 small,同时通过 style 的 --el-switch-on-color--el-switch-off-color 设置开关的背景色。

最后实现效果如下:

暗黑模式

接下来就是实现暗黑模式,暗黑模式的原理就是在 html 节点上添加一个名为 dark 的 class

然后我们设置 dark 的 css 样式即可。我们可以在 main.ts 中引入 Element Plus 官方定义的 css,但是有时候一些元素覆盖不到,所以我们自定义样式。

代码语言:typescript复制
import 'element-plus/theme-chalk/dark/css-vars.css'
// 自定义
import './styles/dark/dark.scss'

在 dark.scss 中,先定义全局的样式变量:

代码语言:css复制
/* 全局默认模式颜色定义 */
:root {
    --background-color: white;
    --background-color-layout: #F5F5F5;
    --text-color: black;
    --primary-color: blue;
    --secondary-color: gray;
    --border-color: #ddd;
    --link-color: blue;
    --button-background-color: #007bff;
    --button-text-color: white;
}

/* 暗黑模式颜色覆盖 */
html.dark {
    --background-color: #121212;
    --background-color-layout: #101112;
    --text-color: white;
    --primary-color: #1e90ff;
    --secondary-color: #aaa;
    --border-color: #333;
    --link-color: #1e90ff;
    --button-background-color: #333;
    --button-text-color: white;
}

/* 全局应用背景和文字颜色 */
body {
    background-color: var(--background-color);
    color: var(--text-color);
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
}

其中,root 和 dark 的变量都是相同的,分别代表亮光和暗黑模式下变量的值。然后在各个组件中,将 background-color 使用上面的变量代替。

接着是在 dark.scss 中定义一些通用组件的文本和背景颜色。

代码语言:css复制
/* 通用元素样式 */
p, a, h1, h2, h3, span, div, i, svg {
    color: var(--text-color);
}

.dark li {
    background-color: var(--background-color);
}
/* 按钮样式 */
button {
    background-color: var(--button-background-color);
    color: var(--button-text-color);
    border: none;
    padding: 10px 20px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

button:hover {
    background-color: var(--primary-color);
}

/* 表单输入框样式 */
input[type="text"], textarea {
    width: 100%;
    padding: 10px;
    border: 1px solid var(--border-color);
    background-color: var(--background-color);
    color: var(--text-color);
}

input[type="text"]:focus, textarea:focus {
    border-color: var(--primary-color);
    outline: none;
}

/* 暗黑模式下元素覆盖样式 */
.dark body, .dark p, .dark a, .dark h1, .dark h2, .dark h3, .dark span, .dark div {
    color: var(--text-color) !important;
}

.dark button {
    background-color: var(--button-background-color) !important;
    color: var(--button-text-color) !important;
}

.dark input[type="text"], .dark textarea {
    background-color: var(--background-color) !important;
    color: var(--text-color) !important;
    border-color: var(--border-color) !important;
}

开关

如果想要在亮光模式和暗黑模式动态切换,这里建议使用 @vue/core 库,这个库算是一个工具库,之前在实现 tabs 栏的时候,用来获取鼠标的坐标。详情可参考文章BuildAdmin08:导航栏tab的滑动块如何实现。

这里主要使用 useDarkuseToggle 来切换暗黑模式。useDark 是一个封装了 Boolean 类型的对象,用来表示是否已经开启暗黑模式(html的class是否添加dark)。

而useToggle就是用来改变useDark的 Boolean 变量,从而控制模式之间的切换。

代码语言:javascript复制
import { useDark, useToggle } from '@vueuse/core'

const isDark = useDark()
if (isDark.value == true) {
    useToggle(isDark)()
}
const toggleDark = useToggle(isDark)

在上面的代码中增加了一个判断,原因就是在暗黑模式下刷新页面,开关已经变成亮光了,但是还是处于暗黑模式下。

分析原因就是 useDark 还是为 ture,所以需要增加判断,手动使用 useToggle 来将其改变为 false,useToggle 返回的是一个函数,所以想要调用还需要后面增加一个括号。下面的 toggleDark返回的就是一个函数,然后绑定到开关的 change 事件上。

最终代码:

切换效果:

细节修复

例如有的图标是 Element Plus 的,有的是本地svg,还有其他的,所以就会出现图标还是黑色的情况。

如果想解决这些颜色问题,就需要对 dark.scss 进行设计。这里对 dark 模式下的 svg 和 fa 标签进行颜色设置。

代码语言:css复制
.dark {
    & svg {
        color: white !important;
    }
    & .fa {
        color: white !important;
    }
}

最终的图标效果:

结语

这就是基于 Element Plus 实现的暗黑模式,当然还有很多细节可以修复,包括设计一些切换时的动画等等,这个下篇文章可以探讨一下。

0 人点赞