🎨 基于 Element Plus 的多主题增强方案:发布我的开源包 @uummxx/element-theme-extended
在做 Vue 3 + Element Plus 项目时,主题定制几乎是每个团队绕不开的需求。
默认 Element Plus 提供的方式主要有:
- ✅ 覆盖 CSS 变量
- ✅ 修改 SCSS 变量重新编译
- ✅ 官方暗黑模式切换
但当你要支持 多品牌主题 / 活动主题 / 高对比度模式 时,这些方式的局限性就暴露出来了:
Element Plus 内部写死了
"base"
作为主色入口,没办法优雅地定义多主题结构。
于是,我对 Element Plus 的主题源码进行了深入改造,并最终封装成一个独立插件 ------
🧩 @uummxx/element-theme-extended
✨ 插件简介
Element Plus 主题扩展包,提供可定制的 SCSS 变量、暗黑/亮色模式支持,以及额外的 mixin,方便快速定制组件库主题。
GitHub: github.com/uummxx/elem...
🌟 功能特性
- 🧱 完全兼容 Element Plus 的 theme-chalk
- 🌞🌚 亮色 / 暗黑主题双模式
- 🎨 支持多主题结构(品牌 A / 品牌 B / Noble / Grand...)
- 🧬 提供 mixin 快速生成颜色层级
- 📦 支持按需引入
- 🪄 零侵入式整合:即插即用
🚀 快速开始
1. 安装
bash
pnpm add @uummxx/element-theme-extended
# 或者
npm install @uummxx/element-theme-extended
# 或者
yarn add @uummxx/element-theme-extended
2. 创建样式文件
新建一个样式文件,例如 styles/element/index.scss
:
scss
// styles/element/index.scss
@forward '@uummxx/element-theme-extended/themes' with (
$themes: (
theme-1: (
primary: red,
success: green
),
theme-2: (
primary: #ccc
)
)
);
// 同时启用亮色与暗黑主题
@use '@uummxx/element-theme-extended/index.scss';
// 只启用亮色主题:
// @use '@uummxx/element-theme-extended/light.scss';
// 只启用暗黑主题:
// @use '@uummxx/element-theme-extended/dark.scss';
3. 在项目中引入
ts
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import './styles/element/index.scss'
import App from './App.vue'
createApp(App).use(ElementPlus).mount('#app')
4. 动态切换主题
ts
import { useThemes } from '@uummxx/element-theme-extended/utils'
const { toggleTheme, toggleDark } = useThemes({ themes: ['theme-1', 'theme-2'] })
toggleTheme('theme-1') // 主题1
toggleTheme('theme-2') // 主题2
toggleTheme('other-theme') // '切换失败' 主题不存在
toggleDark() // 亮色/暗色切换
toggleDark(true) // 暗色主题
toggleDark(false) // 亮色主题
5. 修改element-plus 其他样式(除主题外的样式)
scss
// styles/element/element-plus.scss
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$button-border-radius: (
'large': 30px,
'default': 20px,
'small': 10px,
)
);
⚠️ 注意事项
不要在同一个 SCSS 文件中同时 @forward
官方 Element Plus 样式和 @uummxx/element-theme-extended/utils
的主题工具。
否则可能会出现 Sass 错误:
✅ 正确示例
scss
// a.scss
@forward '@uummxx/element-theme-extended/themes' with (
$themes: (
theme-1: (
primary: red,
success: green,
),
theme-2: (
primary: skyblue,
),
)
);
@use '@uummxx/element-theme-extended/index'; // use dark theme and light theme
// // @use '@uummxx/element-theme-extended/dark'; //use dark theme but need add .dark to html
// // @use '@uummxx/element-theme-extended/light'; // use light theme
scss
// b.scss
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$button-border-radius: (
'large': 30px,
'default': 20px,
'small': 10px,
)
);
❌ 错误示例
scss
// c.scss
@forward '@uummxx/element-theme-extended/themes' with (
$themes: (
theme-1: (
primary: red,
success: green,
),
theme-2: (
primary: skyblue,
),
)
);
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$button-border-radius: (
'large': 30px,
'default': 20px,
'small': 10px,
)
);
@use '@uummxx/element-theme-extended/index'; // use dark theme and light theme
// // @use '@uummxx/element-theme-extended/dark'; //use dark theme but need add .dark to html
// // @use '@uummxx/element-theme-extended/light'; // use light theme
💡 核心原理:打破 "base" 限制
在官方源码中,set-css-color-type
写死了 "base"
作为颜色入口 👇
python
@mixin set-css-color-type($colors, $type) {
@include set-css-var-value(('color', $type), map.get($colors, $type, 'base'));
}
这意味着所有主题色都是基于同一个 "base"
,无法扩展为多套主题。
我将 "base"
抽象成 $theme
参数,使每个主题拥有独立命名空间:
swift
@mixin set-css-color-type($colors, $type, $theme: "base") {
@include set-css-var-value(('color', $type), map.get($colors, $type, $theme));
}
这样我们可以像这样生成多套主题样式:
swift
$themes: (default, simple, grand, noble);
@each $class in $themes {
.#{$class} {
@each $type in (primary, success, warning, danger, info) {
@include set-css-color-type($colors, $type, $class);
}
}
}
从而实现:
.default
默认主题.simple
简约主题.grand
高级主题.noble
深色主题
只需在 HTML 上切换 class,即可全局切换主题。
📦 插件目录结构
csharp
@uummxx/element-theme-extended/
├─ src/
│ ├─ index.scss # SCSS 入口文件
│ ├─ themes.scss # 主题变量
│ ├─ mixins.scss # 主题 mixin
│ ├─ var.scss # 亮色模式变量
│ ├─ function.scss # 生成主题函数
│ ├─ main.ts # TS/JS 入口
│ ├─ utils.ts # TS/JS 工具函数
│ └─ dark/
│ ├─ var.scss # 暗色主题变量
│ └─ css_var.scss # 暗黑模式变量
├─ eslint.config.mjs # eslint 配置
├─ package.json
└─ README.md
🎥 效果演示
在运行项目中执行:
scss
toggleTheme('theme-2')
即可立即看到主色、成功色、警告色等 Element Plus 组件色系全局切换。
配合官方暗黑模式,还能得到 theme-2 dark
的组合模式效果 🔥
💬 开发灵感
在项目中,我最初只是想实现一个"蓝色版"和"绿色版"主题,但发现 Element Plus 的主题体系几乎是单通道的。
后来我逐行阅读了 theme-chalk 源码,发现关键在于:
set-css-color-type
set-color-mix-level
这两个 mixin 写死了 "base"
。
于是我通过 $theme
参数重构了配色生成逻辑,并将它封装成独立 npm 包。
🏁 总结
如果你正在用 Element Plus,希望拥有:
✅ 多品牌配色
✅ 明暗模式共存
✅ 自动计算颜色层级
✅ 无需重复维护的主题体系
那这个包会让你的主题系统焕然一新。
🧡 如果这篇文章对你有帮助,记得点个赞 👍 + 收藏 ⭐
想了解更多主题系统原理,可以在评论区交流~