在实际项目开发中,我们经常会遇到这样的需求:全局统一管理主题色 ,并且希望能 动态切换主题色(比如黑暗模式 / 品牌色切换)。
本文将手把手教你在 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
文件,避免分散。 -
工具函数封装 :封装
applyTheme
和initTheme
,方便全局调用。 -
持久化存储 :使用
localStorage
保存用户选择的主题,下次打开应用自动加载。 -
随时扩展新主题 :只需在
themes.js
中新增配置即可,完全不影响现有逻辑。
这样不仅能实现多主题切换,还能保证用户体验和项目可维护性,真正做到 企业级主题管理方案。
最终效果
-
.vue
文件里可以直接用var(--primary-color)
或$primary-color
。 -
点击按钮时,通过
applyTheme(theme)
方法切换不同的主题配置。 -
所有使用 CSS 变量的组件样式会 即时更新,无需刷新页面。
-
用户选择的主题会存储到
localStorage
,下次打开自动应用。
结语
通过本文的实践,你已经学会了如何在 Vue + Vite + Element UI 中利用 :root
+ SCSS 变量 来实现一个优雅的动态主题切换方案。
这套方案比 Element UI 官方的换肤方案更轻量,不需要重新构建样式文件,真正做到 即点即换肤
如果你觉得这篇文章对你有帮助,欢迎点赞 + 收藏,有问题也可以在评论区交流!