前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BuildAdmin18:网站一键切换暗黑模式,到底是如何实现的

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

原创
作者头像
叫我阿柒啊
修改2024-09-10 07:58:56
400
修改2024-09-10 07:58:56
举报
文章被收录于专栏:vue前端之路入门到放弃之路

前言

之前的菜单栏想按照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 实现的暗黑模式,当然还有很多细节可以修复,包括设计一些切换时的动画等等,这个下篇文章可以探讨一下。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 切换按钮
    • 开关图标
    • 暗黑模式
    • 开关
    • 细节修复
    • 结语
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档