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

✅ 多品牌配色

✅ 明暗模式共存

✅ 自动计算颜色层级

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

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


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

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

相关推荐
小马哥编程10 小时前
【软考架构】案例分析-Web应用设计(应用服务器概念)
前端·架构
鱼与宇10 小时前
苍穹外卖-VUE
前端·javascript·vue.js
啃火龙果的兔子10 小时前
前端直接渲染Markdown
前端
z-robot10 小时前
Nginx 配置代理
前端
用户479492835691510 小时前
Safari 中文输入法的诡异 Bug:为什么输入 @ 会变成 @@? ## 开头 做 @ 提及功能的时候,测试同学用 Safari 测出了个奇怪的问题
前端·javascript·浏览器
没有故事、有酒10 小时前
Ajax介绍
前端·ajax·okhttp
朝新_11 小时前
【SpringMVC】详解用户登录前后端交互流程:AJAX 异步通信与 Session 机制实战
前端·笔记·spring·ajax·交互·javaee
裴嘉靖11 小时前
Vue 生成 PDF 完整教程
前端·vue.js·pdf
毕设小屋vx ylw28242611 小时前
Java开发、Java Web应用、前端技术及Vue项目
java·前端·vue.js
冴羽11 小时前
今日苹果 App Store 前端源码泄露,赶紧 fork 一份看看
前端·javascript·typescript