创建主题管理模块(用于配置颜色变量)
新建 src/utils/theme.ts
import { ref, watchEffect } from 'vue'
type ThemeType = 'light' | 'dark' | 'system'
// 主题配置
const themeConfig = {
light: {
'--el-color-primary': '#409eff',
'--bg-color': '#ffffff',
'--text-color': '#303133'
},
dark: {
'--el-color-primary': '#79bbff',
'--bg-color': '#141414',
'--text-color': '#e5eaf3'
}
}
// 状态管理
const theme = ref<ThemeType>(localStorage.getItem('theme') as ThemeType || 'light')
// 监听系统主题变化
const systemThemeMatch = window.matchMedia('(prefers-color-scheme: dark)')
// 获取当前生效主题
const getRealTheme = () => {
if (theme.value === 'system') {
return systemThemeMatch.matches ? 'dark' : 'light'
}
return theme.value
}
// 应用主题
const applyTheme = (themeType: 'light' | 'dark') => {
const variables = themeConfig[themeType]
Object.entries(variables).forEach(([key, value]) => {
document.documentElement.style.setProperty(key, value)
})
document.documentElement.className = themeType
}
// 初始化监听
const initThemeListener = () => {
systemThemeMatch.addEventListener('change', () => {
if (theme.value === 'system') {
applyTheme(getRealTheme())
}
})
}
// 切换主题
const toggleTheme = (newTheme: ThemeType) => {
theme.value = newTheme
localStorage.setItem('theme', newTheme)
applyTheme(getRealTheme())
}
export function useTheme() {
return {
theme,
toggleTheme,
initThemeListener
}
}
全局样式配置
新建 src/styles/theme.scss
:root {
// 默认亮色主题变量
@each $name, $color in $light-theme {
--#{$name}: #{$color};
}
// 动态背景色和文字颜色
background-color: var(--bg-color);
color: var(--text-color);
// Element Plus组件样式覆盖
.el-button {
background-color: var(--bg-color);
color: var(--text-color);
}
// 添加其他需要自定义的组件样式...
}
主题切换组件
新建 src/components/ThemeSwitch.vue
<template>
<el-dropdown @command="handleCommand">
<el-icon :size="20"><Setting /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="light" :disabled="theme === 'light'">
<el-icon><Sunny /></el-icon> 亮色模式
</el-dropdown-item>
<el-dropdown-item command="dark" :disabled="theme === 'dark'">
<el-icon><Moon /></el-icon> 暗黑模式
</el-dropdown-item>
<el-dropdown-item command="system" :disabled="theme === 'system'">
<el-icon><Monitor /></el-icon> 跟随系统
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script setup lang="ts">
import { useTheme } from '@/utils/theme'
import { Sunny, Moon, Monitor, Setting } from '@element-plus/icons-vue'
const { theme, toggleTheme } = useTheme()
const handleCommand = (command: string) => {
toggleTheme(command as ThemeType)
}
</script>
初始化配置
在 main.ts
中添加:
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import { useTheme } from './utils/theme'
const app = createApp(App)
// 初始化主题
const { initThemeListener, applyTheme, getRealTheme } = useTheme()
app.use(ElementPlus, {
zIndex: 3000,
size: 'default',
theme: getRealTheme()
})
applyTheme(getRealTheme())
initThemeListener()
app.mount('#app')
核心实现原理
CSS变量控制:通过修改documentElement的CSS Variables实现动态换肤
响应式存储:使用localStorage保存用户选择,结合Vue3的响应式系统
系统主题监听:通过window.matchMedia检测系统主题变化
Element Plus整合:根据主题动态设置Element组件库的基础配置