element-plus 自定义主题 最佳实践

🎨 基于 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,希望拥有:

✅ 多品牌配色

✅ 明暗模式共存

✅ 自动计算颜色层级

✅ 无需重复维护的主题体系

那这个包会让你的主题系统焕然一新。


🧡 如果这篇文章对你有帮助,记得点个赞 👍 + 收藏 ⭐

想了解更多主题系统原理,可以在评论区交流~

相关推荐
CodeCraft Studio3 小时前
国产化PDF处理控件Spire.PDF教程:C#中轻松修改 PDF 文档内容
前端·pdf·c#·.net·spire.pdf·编辑pdf·修改pdf
晴殇i3 小时前
告别 localStorage!探索前端存储新王者 IndexedDB
前端·javascript·面试
Mintopia3 小时前
Next.js 的分布式基础思想:从 CAP 到事件风暴,一路向“可扩展”的银河系巡航
前端·javascript
Moment3 小时前
Next.js 16 Beta:性能、架构与开发体验全面升级 💯💯💯
前端·javascript·github
FIN66683 小时前
昂瑞微:引领射频前端国产化浪潮,铸就5G时代核心竞争力
前端·人工智能·科技·5g·芯片·卫星
一枚前端小能手3 小时前
🔄 模块化方案选择困难症?JavaScript模块化演进史与最佳实践深度解析
前端·javascript
JarvanMo3 小时前
Flutter 登上大屏幕:LG 如何将 Flutter 带到 webOS 智能电视
前端
巴博尔3 小时前
自定义tabs+索引列表,支持左右滑动切换
前端·uniapp
诗句藏于尽头4 小时前
音乐播放器-单html文件
前端·html