340 字
2 分钟
theme-switch
主题切换
1、 CSS自定义属性
定义主题变量
:root { /** 默认亮色主题 */ --primary-color: #3b82f6; --bg-color: #ffffff; --text-color: #1f2937; --border-color: #e5e7eb; --card-bg: #f9fafb;}[data-theme='dark']{ /** 暗色主题 */ --primary-color: #60a5fa; --bg-color: #1f2937; --text-color: #f9fafb; --border-color: #374151; --card-bg: #374151;}[data-theme="blue"] { /* 蓝色主题 */ --primary-color: #1e40af; --bg-color: #eff6ff; --text-color: #1e3a8a; --border-color: #bfdbfe; --card-bg: #dbeafe;}/* @media (prefers-color-scheme: dark) { } */body{ background-color: var(--bg-color); color: var(--text-color); transition: all 0.5s ease;}.card{ background-color: var(--card-bg); border-color: var(--border-color);}.btn-primary{ background-color: var(--primary-color); color: white;} import { ref, watch } from 'vue';
export type ThemeType = 'light' | 'dark' | 'blue';
const THEME_KEY = 'app-theme';
export const useTheme = () => { const currentTheme = ref<ThemeType>( (localStorage.getItem(THEME_KEY) as ThemeType) || 'light' );
// 应用主题到 DOM const applyTheme = (theme: ThemeType) => { document.documentElement.setAttribute('data-theme', theme); };
// 切换主题 const setTheme = (theme: ThemeType) => { currentTheme.value = theme; applyTheme(theme); localStorage.setItem(THEME_KEY, theme); };
// 监听主题变化 watch(currentTheme, (newTheme) => { applyTheme(newTheme); }, { immediate: true });
// 获取所有可用主题 const availableThemes = ref<{ key: ThemeType; label: string }[]>([ { key: 'light', label: '亮色模式' }, { key: 'dark', label: '深色模式' }, { key: 'blue', label: '蓝色模式' } ]);
return { currentTheme: readonly(currentTheme), setTheme, availableThemes }; }; <template> <div class="theme-toggle"> <button v-for="theme in availableThemes" :key="theme.key" @click="setTheme(theme.key)" :class="['theme-btn', { active: currentTheme === theme.key }]" > {{ theme.label }} </button> </div> </template>
<script setup lang="ts"> import { useTheme } from '@/composables/useTheme';
const { currentTheme, setTheme, availableThemes } = useTheme(); </script>
<style scoped> .theme-toggle { display: flex; gap: 8px; padding: 4px; background: var(--card-bg); border-radius: 8px; border: 1px solid var(--border-color); }
.theme-btn { padding: 8px 16px; border: none; border-radius: 6px; background: transparent; color: var(--text-color); cursor: pointer; transition: all 0.2s ease; }
.theme-btn:hover { background: var(--border-color); }
.theme-btn.active { background: var(--primary-color); color: white; } </style> theme-switch
https://fuwari.vercel.app/posts/theme-switch/