Vue + Vite + Element UI 实现动态主题切换:基于 :root + SCSS 变量的最佳实践

在实际项目开发中,我们经常会遇到这样的需求:全局统一管理主题色 ,并且希望能 动态切换主题色(比如黑暗模式 / 品牌色切换)。

本文将手把手教你在 Vue + Vite + Element UI 项目中,结合 SCSS + :root + CSS 变量 来实现一个优雅的全局主题方案,并提供 多主题最佳实践


一、项目结构(示例)

javascript 复制代码
your-project/
│
├─ src/
│   ├─ styles/
│   │   ├─ variables.scss       # SCSS 变量文件
│   │   └─ theme.scss           # :root CSS 变量文件
│   ├─ utils/
│   │   └─ theme.js             # 主题切换工具
│   ├─ App.vue
│   └─ main.js
├─ vite.config.js
└─ package.json

二、定义全局 SCSS 变量

src/styles/variables.scss

css 复制代码
// SCSS 变量
$primary-color: #409EFF;
$success-color: #67C23A;
$warning-color: #E6A23C;
$danger-color: #F56C6C;
$info-color: #909399;

$font-size-base: 16px;

三、利用 :root 定义全局 CSS 变量

src/styles/theme.scss

css 复制代码
@import './variables.scss';

:root {
  --primary-color: #{$primary-color};
  --success-color: #{$success-color};
  --warning-color: #{$warning-color};
  --danger-color: #{$danger-color};
  --info-color: #{$info-color};
  --font-size-base: #{$font-size-base};
}

这样,全局样式中就可以用 var(--primary-color) 来访问这些变量。


四、在 Vite 中全局引入 SCSS

vite.config.js

javascript 复制代码
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue2';
import path from 'path';

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `
          @import "@/styles/variables.scss";
          @import "@/styles/theme.scss";
        `
      }
    }
  }
});

这样所有 .scss 文件和 .vue 文件的 <style lang="scss"> 都会自动拥有全局变量。


五、入口文件配置

main.js

javascript 复制代码
import Vue from 'vue';
import App from './App.vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import { initTheme } from '@/utils/theme';

Vue.use(ElementUI);

// 初始化主题(从 localStorage 读取)
initTheme();

new Vue({
  render: h => h(App),
}).$mount('#app');

六、基础实现:在 Vue 组件中使用

App.vue

javascript 复制代码
<template>
  <div class="app">
    <el-button class="my-button">Primary Button</el-button>
    <el-button class="success-button">Success Button</el-button>
    <br /><br />
    <el-button @click="changeTheme('red')">切换为红色主题</el-button>
    <el-button @click="changeTheme('blue')">切换为蓝色主题</el-button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    // 更优雅的动态切换主题方法
    changeTheme(theme = 'red') {
      const themes = {
        red: {
          '--primary-color': '#F56C6C',
          '--success-color': '#67C23A'
        },
        blue: {
          '--primary-color': '#409EFF',
          '--success-color': '#67C23A'
        },
        dark: {
          '--primary-color': '#303133',
          '--success-color': '#909399'
        }
      };

      const selectedTheme = themes[theme] || themes.red;
      Object.keys(selectedTheme).forEach(key => {
        document.documentElement.style.setProperty(key, selectedTheme[key]);
      });
    }
  }
};
</script>

<style lang="scss">
.my-button {
  background-color: var(--primary-color);
  color: #fff;
}

.success-button {
  background-color: var(--success-color);
  color: #fff;
}

/* 覆盖 Element UI 默认主题色 */
.el-button {
  border-color: var(--primary-color);
}
</style>

七、多主题配置最佳实践

上面的 changeTheme 方法虽然能实现切换,但如果主题多了会很难维护。更好的方式是 集中管理主题配置


1️⃣ 预设主题配置对象

src/styles/themes.js

javascript 复制代码
export const themes = {
  red: {
    '--primary-color': '#F56C6C',
    '--success-color': '#67C23A',
    '--background-color': '#FFF4F0',
    '--text-color': '#B02D10'
  },
  blue: {
    '--primary-color': '#409EFF',
    '--success-color': '#67C23A',
    '--background-color': '#F5F8FF',
    '--text-color': '#2254C5'
  },
  dark: {
    '--primary-color': '#303133',
    '--success-color': '#909399',
    '--background-color': '#141414',
    '--text-color': '#E5E5E5'
  }
};

2️⃣ 封装一个主题工具方法

src/utils/theme.js

javascript 复制代码
import { themes } from '@/styles/themes';

export function applyTheme(themeName = 'red') {
  const selectedTheme = themes[themeName] || themes.red;
  Object.keys(selectedTheme).forEach(key => {
    document.documentElement.style.setProperty(key, selectedTheme[key]);
  });

  // 存储到 localStorage,保证刷新后主题不丢失
  localStorage.setItem('app-theme', themeName);
}

export function initTheme() {
  const savedTheme = localStorage.getItem('app-theme') || 'red';
  applyTheme(savedTheme);
}

3️⃣ 在组件中调用

javascript 复制代码
<template>
  <div>
    <el-button @click="setTheme('red')">红色主题</el-button>
    <el-button @click="setTheme('blue')">蓝色主题</el-button>
    <el-button @click="setTheme('dark')">暗黑主题</el-button>
  </div>
</template>

<script>
import { applyTheme } from '@/utils/theme';

export default {
  methods: {
    setTheme(themeName) {
      applyTheme(themeName);
    }
  }
};
</script>

八、最佳实践总结

  • 集中管理主题配置 :所有主题色值放在一个 themes.js 文件,避免分散。

  • 工具函数封装 :封装 applyThemeinitTheme,方便全局调用。

  • 持久化存储 :使用 localStorage 保存用户选择的主题,下次打开应用自动加载。

  • 随时扩展新主题 :只需在 themes.js 中新增配置即可,完全不影响现有逻辑。

这样不仅能实现多主题切换,还能保证用户体验和项目可维护性,真正做到 企业级主题管理方案


最终效果

  • .vue 文件里可以直接用 var(--primary-color)$primary-color

  • 点击按钮时,通过 applyTheme(theme) 方法切换不同的主题配置。

  • 所有使用 CSS 变量的组件样式会 即时更新,无需刷新页面。

  • 用户选择的主题会存储到 localStorage,下次打开自动应用。


结语

通过本文的实践,你已经学会了如何在 Vue + Vite + Element UI 中利用 :root + SCSS 变量 来实现一个优雅的动态主题切换方案。

这套方案比 Element UI 官方的换肤方案更轻量,不需要重新构建样式文件,真正做到 即点即换肤

如果你觉得这篇文章对你有帮助,欢迎点赞 + 收藏,有问题也可以在评论区交流!

相关推荐
Tachyon.xue7 小时前
Vue 3 项目集成 Element Plus + Tailwind CSS 详细教程
前端·css·vue.js
我命由我123458 小时前
Photoshop - Photoshop 工具从工具栏消失
笔记·学习·ui·职场和发展·职场发展·photoshop·ps
FuckPatience8 小时前
Vue 中‘$‘符号含义
前端·javascript·vue.js
这里是杨杨吖14 小时前
SpringBoot+Vue医院预约挂号系统 附带详细运行指导视频
vue.js·spring boot·医院·预约挂号
光影少年16 小时前
vue打包优化方案都有哪些?
前端·javascript·vue.js
大美B端工场-B端系统美颜师16 小时前
从“如何画”到“为何画”:AIGC倒逼UI设计师回归设计本源
ui·回归·aigc
木易 士心20 小时前
Ref 和 Reactive 响应式原理剖析与代码实现
前端·javascript·vue.js
被巨款砸中20 小时前
一篇文章讲清Prompt、Agent、MCP、Function Calling
前端·vue.js·人工智能·web
rggrgerj1 天前
Vue3 组件完全指南代码
前端·javascript·vue.js
在逃的吗喽1 天前
Vue3新变化
前端·javascript·vue.js