一、前言
Element Plus 实战篇收官篇。064 篇说过组件库颜色全靠 CSS 变量------本篇吃透这套变量体系:一行引入暗黑模式、一个组合式函数管切换、一个输入框换主题色,让 068 篇的后台骨架白天黑夜都好看。
二、原理一分钟:class 一挂,变量全变
Element Plus 的暗黑方案极其简单:官方提供一份"暗黑变量表",html 标签挂上 class="dark" 时生效。
text
:root { --el-bg-color: #ffffff; ... } ← 亮色(默认)
html.dark { --el-bg-color: #141414; ... } ← 暗黑(挂 class 后命中)
组件内部全部引用变量(--el-bg-color、--el-text-color-primary......),没有任何组件代码需要改------变量变了,全库换装。我们自己的样式只要也用变量写(064 篇埋的规矩),就能一起切换。
三、三步接入暗黑模式
3.1 引入暗黑变量表
ts
// src/main.ts
import 'element-plus/theme-chalk/dark/css-vars.css' // ★ 暗黑变量表,引一次即可
3.2 封装 useDarkMode 组合式函数
036 篇封装 useToggle 的实战版------主题状态 + 持久化 + class 同步:
ts
// src/composables/useDarkMode.ts
import { ref, watchEffect } from 'vue'
// 模块级状态:所有组件共享同一份(和 store 单例同理,039 篇最佳实践)
const THEME_KEY = 'theme'
const isDark = ref(localStorage.getItem(THEME_KEY) === 'dark')
// 自动依赖收集:isDark 变化 → 三个副作用全执行
watchEffect(() => {
// 1. class 挂在 html(documentElement)上,★ 不是 body
document.documentElement.classList.toggle('dark', isDark.value)
// 2. 持久化,刷新不丢(057 篇手动持久化的迷你版)
localStorage.setItem(THEME_KEY, isDark.value ? 'dark' : 'light')
})
export function useDarkMode() {
function toggleDark() {
isDark.value = !isDark.value
}
return { isDark, toggleDark }
}
3.3 放进 Layout 顶部栏
vue
<!-- Layout.vue header 里加一个开关 -->
<el-switch
v-model="isDark"
inline-prompt
active-icon="Moon"
inactive-icon="Sunny"
/>
<script setup lang="ts">
import { useDarkMode } from '@/composables/useDarkMode'
const { isDark, toggleDark } = useDarkMode() // switch 的 v-model 直接绑 isDark
</script>
【截图位置:拨动开关,整个后台瞬间变暗;刷新后仍是暗黑】
四、动态主题色:setProperty 一行搞定
064 篇在 CSS 里覆盖 --el-color-primary 是"写死"的;运行时切换用 JS 设置变量:
vue
<template>
<el-color-picker v-model="primaryColor" @change="setPrimary" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const primaryColor = ref('#409eff')
function setPrimary(color: string | null) {
if (!color) return
const el = document.documentElement
// ★ 主色一改,按钮/链接/选中态全变
el.style.setProperty('--el-color-primary', color)
// 衍生色简单方案:用 color-mix 按比例混白/混黑(现代浏览器支持)
el.style.setProperty('--el-color-primary-light-3', `color-mix(in srgb, ${color} 70%, white)`)
el.style.setProperty('--el-color-primary-dark-2', `color-mix(in srgb, ${color} 80%, black)`)
}
</script>
想重启也保持?把 color 一起存 localStorage,初始化时读出来再 setProperty------套路和 isDark 一模一样,留给你练手(系列一贯的"差一步"作业)。
五、自定义样式怎么配合
用变量写的样式自动适配,写死颜色的样式暗黑下刺眼:
css
/* ❌ 写死:暗黑下白底白字灾难 */
.my-card { background: #fff; color: #303133; border: 1px solid #dcdfe6; }
/* ✅ 变量:亮暗自动切换 */
.my-card {
background: var(--el-bg-color); /* 卡片底色 */
color: var(--el-text-color-primary); /* 主文字 */
border: 1px solid var(--el-border-color); /* 边框 */
}
常用变量速查:
| 变量 | 用途 |
|---|---|
| --el-bg-color / --el-bg-color-page | 组件底色 / 页面底色 |
| --el-text-color-primary / regular / secondary | 文字三档 |
| --el-border-color | 边框 |
| --el-fill-color-light | 浅填充(hover 背景) |
| --el-color-primary 系列 | 主题色及其衍生 |
六、踩坑记录
- dark class 挂到 body :变量表选择器是
html.dark,挂 body 不生效------必须document.documentElement - 忘了引 dark/css-vars.css:class 挂了但没暗黑效果------变量表都没加载,调什么都是白搭
- 切换按钮绑了 toggleDark 却传了 isDark :el-switch 用
v-model="isDark",toggleDark 适合图标按钮@click,两种用法别混 - 白屏闪一下再变暗:初始化在组件 setup 才挂 class------把 class 恢复逻辑提前到 main.ts / index.html 内联脚本,加载即暗
- 部分页面没跟随变暗:那些页面写死了 #fff/#000------全局搜索硬编码色值,替换成 CSS 变量(这是接暗黑的最大工作量)
- 第三方图表颜色不适配:ECharts 等自己画 canvas 的库不吃 CSS 变量------切换时把主题色传给图表配置(080 篇会再遇)
七、今日小结
- 暗黑三步:引 dark/css-vars.css → html 挂 class="dark" → 自己样式用变量
- 切换器:useDarkMode 组合式函数(模块级单例 + watchEffect + localStorage),036/039 篇的落地样板
- 动态主题色:setProperty('--el-color-primary', color),衍生色用 color-mix
- 铁律:自写样式禁止写死色值,全走 --el-xxx 变量
下篇预告
Element Plus 篇完结,进入性能优化篇:组件懒加载与异步组件按需加载------为什么首屏越来越慢?怎么让用户"看到哪加载到哪"?下一篇 072 性能优化开篇。