340 字
2 分钟
theme-switch

主题切换#

1、 CSS自定义属性#

定义主题变量

/src/styles/theme.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;
}
src/composables/useTheme.ts
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
};
};
src/components/ThemeToggle.vue
<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/
作者
Lorem Ipsum
发布于
2025-09-08
许可协议
CC BY-NC-SA 4.0