vue3 + Element Plus 系统主题切换

创建主题管理模块(用于配置颜色变量)

新建 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组件库的基础配置

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值