一、项目背景

新目标:完成设置页面中“主题模式”切换功能,支持在明亮模式与黑夜模式之间自由切换。通过设置全局theme实现。

二、功能实现

主题模式的切换功能位于 SettingsView 中。因此,第一步需要梳理 SettingsView 内部的控制逻辑,明确当前页面是如何实现模式切换的,包括状态的存储方式(如 localStorage 或全局状态管理)、切换触发组件(如下拉框、开关按钮)以及样式应用机制(通过 class 切换或 CSS 变量)。在此基础上,再进行功能实现和优化。

<el-switch v-model="isDarkMode" @change="handleThemeChange">
    <template #active-action>
        <span class="custom-active-action"><el-icon><MoonNight /></el-icon></span>
    </template>
    <template #inactive-action>
        <span class="custom-inactive-action"><el-icon><Sunrise /></el-icon></span>
    </template>
</el-switch>

在本功能中,采用 el-switch 组件作为主题模式的切换控件。为了提升界面美观度,滑块部分引入了 el-icon 图标进行装饰,也可以根据实际需求,自行替换为更符合设计风格的图标或元素。

import { Sunrise, MoonNight } from '@element-plus/icons-vue'

export default {
    components:{
        Sunrise,  
        MoonNight
      },
    setup(props, { emit }) {

        const isDarkMode = ref(false)
    
        // 初始化主题
        const initTheme = () => {
          const savedTheme = localStorage.getItem('theme') || 'light'
          isDarkMode.value = savedTheme === 'dark'
          document.documentElement.setAttribute('data-theme', savedTheme)
        }
    
        // 页面加载时初始化主题
        initTheme()
    
        const handleThemeChange = (value) => {
            const theme = value ? 'dark' : 'light'
            document.documentElement.setAttribute('data-theme', theme)
            localStorage.setItem('theme', theme)
            isDarkMode.value = value
        }
}

此处仅展示了关键代码片段。由于示例中使用到了 icon 图标,请确保在文件中正确导入相关图标,并在 components 中完成声明后再进行使用。

主题的初始化逻辑如下:

  1. 优先从 localStorage 中读取已保存的 theme 值;

  2. 如果用户从未使用过或未曾设置过主题,则默认使用 明亮模式(light);

  3. 根据获取到的 theme 值,确定 el-switch 的初始状态(true 表示深色模式,false 表示明亮模式)。

document.documentElement.setAttribute('data-theme', savedTheme)

这句看不懂没关系,先放着,后面有讲。

当前已经完成了全局主题颜色的配置,下一步是让所有页面根据主题自动切换颜色。

  1. 创建 theme.css 文件,作为全局样式文件,定义明亮模式和深色模式下的各类颜色变量;

    * 明亮模式 - 默认样式 */
    :root {
      --el-bg-color: #ffffff;
      --el-text-color-primary: #303133;
      --el-text-color-regular: #606266;
      --el-text-color-secondary: #909399;
      --el-text-color-placeholder: #c0c4cc;
      --el-border-color-base: #dcdfe6;
      --el-border-color-light: #e4e7ed;
      --el-border-color-lighter: #ebeef5;
      --el-border-color-extra-light: #f2f6fc;
    }
    
    /* 黑夜模式 */
    [data-theme="dark"] {
      --el-bg-color: #1a1a1a;
      --el-text-color-primary: #ffffff;
      --el-text-color-regular: #e4e7ed;
      --el-text-color-secondary: #cfd3dc;
      --el-text-color-placeholder: #a3a6ad;
      --el-border-color-base: #4c4d4f;
      --el-border-color-light: #414243;
      --el-border-color-lighter: #363637;
      --el-border-color-extra-light: #2b2b2c;
    }
    /* CloudView 主题样式 */
    [data-theme="dark"] .cloud-container {
        background-color: var(--el-fill-color-base) !important;
      }
      
      [data-theme="dark"] .sidebar {
        background-color: var(--el-bg-color) !important;
        border-color: var(--el-border-color-base) !important;
      }
      
      [data-theme="dark"] .main-content {
        background-color: var(--el-bg-color) !important;
      }

    上述内容仅展示了 theme.css 中的部分代码,暂时不必完全理解,后面会进行详细讲解。

  2. main.js 中引入该样式文件,确保整个项目的组件和页面都能访问到这些全局样式,实现统一的主题响应。

    import './styles/theme.css'

至此,全局样式配置已完成,主题切换功能已经可以在整个项目中生效。功能效果示意图如下所示:

三、详细讲解

1.document.documentElement.setAttribute('data-theme', savedTheme)

document.documentElement.setAttribute('data-theme', savedTheme)

代码分解:

  • document:代表整个 HTML 文档
  • documentElement:指的是文档的根元素,也就是 <html> 标签
  • setAttribute():设置 HTML 元素的属性
  • 'data-theme':属性名
  • savedTheme:属性值('dark' 或 'light')

这行代码会在 <html> 标签上添加一个 data-theme 属性

明亮模式时:

<html data-theme="light">
  <!-- 页面内容 -->
</html>

黑夜模式时:

<html data-theme="dark">
  <!-- 页面内容 -->
</html>

有了这个属性,我们就可以使用 CSS 选择器来应用不同的样式:

/* 明亮模式样式(默认) */
.title {
  background-color: white;
  color: black;
}

/* 黑夜模式样式 */
[data-theme="dark"] .title {
  background-color: black;
  color: white;
}

通过这种方式,可以针对同一个 class,根据当前主题应用不同的样式,实现主题间的样式切换。

2.:root

:root {
  --el-bg-color: #ffffff;
  --el-text-color-primary: #303133;
  --el-border-color-extra-light: #f2f6fc;
}

:root 指的是根元素,在 HTML 中,根元素就是 <html> 标签,所以 :root 等价于 html 选择器。示例如下:

<html>  <!-- 这就是根元素 -->
  <body>
    <div>内容</div>
  </body>
</html>

:root {
  /* 这里的样式会应用到 <html> 标签 */
}

/* 等价于 */
html {
  /* 同样的效果 */
}

3.--el-bg-color: #ffffff;

 --el-bg-color: #ffffff;

--el-bg-color: #ffffff; 只是定义了一个 CSS 变量,它本身不会改变任何元素的背景颜色,需要使用这个变量才能生效。使用方法如下示例:

:root {
  --el-bg-color: #ffffff;  /* 定义变量 */
}

/* 使用变量 */
.my-element {
  background-color: var(--el-bg-color);  /* 使用变量 */
}

/* 实际效果 */
.my-element {
  background-color: #ffffff;  /* 背景变为 #ffffff */
}

4.为什么是--el-bg-color?这是固定的吗?还是可以起别的名字?

可以起别的名字!但建议保持 --el- 前缀

/* CSS 变量命名规则: */

:root {
  /* 可以自定义变量名 */
  --my-bg-color: #ffffff;
  --primary-color: #409eff;
  --custom-text-color: #333333;
  
  /* Element Plus 官方变量名 */
  --el-bg-color: #ffffff;
  --el-text-color-primary: #303133;
}

/* 使用自定义变量: */
.my-element {
  background-color: var(--my-bg-color);
  color: var(--custom-text-color);
}

为什么建议保持 --el- 前缀:

  • Element Plus 组件使用这些变量
  • 保持一致性,便于维护
  • 避免与 Element Plus 内部变量冲突

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐