415 lines
8.9 KiB
Markdown
415 lines
8.9 KiB
Markdown
# 主题系统使用指南
|
||
|
||
## 概述
|
||
|
||
项目已成功集成完整的亮色/暗色主题系统,支持一键切换并自动保存用户偏好。
|
||
|
||
## ✨ 主要特性
|
||
|
||
- ✅ 完整的亮色和暗色主题定义
|
||
- ✅ 自动检测系统主题偏好
|
||
- ✅ 用户偏好持久化(localStorage)
|
||
- ✅ 监听系统主题变化
|
||
- ✅ 平滑的过渡动画
|
||
- ✅ 50+ CSS 变量覆盖所有UI场景
|
||
- ✅ TypeScript 类型支持
|
||
- ✅ 响应式数据绑定
|
||
|
||
## 🚀 快速开始
|
||
|
||
### 1. 全局初始化(已完成)
|
||
|
||
主题系统已在 `App.vue` 中全局初始化,整个应用自动支持主题切换功能。
|
||
|
||
### 2. 主题切换按钮
|
||
|
||
在头部工具栏可以看到主题切换按钮(🌙/☀️图标),点击即可切换主题。
|
||
|
||
### 3. 手动切换主题
|
||
|
||
```typescript
|
||
import { useTheme } from '@/utils/theme';
|
||
|
||
// 在组件中使用
|
||
const { toggle, setTheme, currentTheme, isDark } = useTheme();
|
||
|
||
// 切换主题
|
||
toggle();
|
||
|
||
// 设置为特定主题
|
||
setTheme('dark'); // 或 'light'
|
||
|
||
// 获取当前主题状态
|
||
console.log(isDark()); // true 或 false
|
||
console.log(currentTheme); // 'light' 或 'dark'
|
||
```
|
||
|
||
### 4. 在样式文件中使用主题变量
|
||
|
||
```scss
|
||
.my-component {
|
||
background: var(--background-color);
|
||
color: var(--text-color);
|
||
border: 1px solid var(--border-color);
|
||
|
||
&:hover {
|
||
background: var(--background-hover);
|
||
border-color: var(--border-color-hover);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📋 可用的 CSS 变量
|
||
|
||
### 主题标识
|
||
- `--theme-mode`: 当前主题模式 ('light' 或 'dark')
|
||
|
||
### 主要颜色
|
||
- `--primary-color`, `--primary-hover`, `--primary-active`
|
||
- `--secondary-color`, `--secondary-hover`, `--secondary-active`
|
||
- `--accent-color`, `--accent-hover`
|
||
|
||
### 背景颜色
|
||
- `--background-color`: 主要背景
|
||
- `--background-secondary`, `--background-tertiary`
|
||
- `--background-hover`
|
||
|
||
### 文本颜色
|
||
- `--text-color`: 主要文本
|
||
- `--text-secondary`, `--text-tertiary`
|
||
- `--text-inverse`: 反转文本色
|
||
|
||
### 边框颜色
|
||
- `--border-color`, `--border-color-hover`, `--border-color-active`
|
||
|
||
### 状态颜色
|
||
- `--success-color`, `--success-bg`
|
||
- `--warning-color`, `--warning-bg`
|
||
- `--error-color`, `--error-bg`
|
||
- `--info-color`, `--info-bg`
|
||
|
||
### 组件颜色
|
||
- `--card-bg`, `--card-shadow`
|
||
- `--sidebar-bg`, `--sidebar-hover`
|
||
- `--header-bg`
|
||
|
||
### 阴影
|
||
- `--shadow-sm`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`
|
||
|
||
### 圆角
|
||
- `--border-radius`, `--border-radius-sm`
|
||
- `--border-radius-lg`, `--border-radius-xl`
|
||
- `--border-radius-full`
|
||
|
||
### 过渡
|
||
- `--transition-base`: all 0.3s
|
||
- `--transition-fast`: all 0.15s
|
||
- `--transition-slow`: all 0.5s
|
||
|
||
### 字体
|
||
- `--font-family-base`
|
||
|
||
## 🎨 自定义滚动条
|
||
|
||
项目已经内置了自定义滚动条样式,支持主题切换:
|
||
|
||
### 特性
|
||
- ✅ 自动适配亮色/暗色主题
|
||
- ✅ 支持 WebKit 和 Firefox 浏览器
|
||
- ✅ 平滑的过渡动画
|
||
- ✅ 悬停效果增强
|
||
- ✅ 支持隐藏滚动条(保持滚动功能)
|
||
|
||
### 滚动条大小
|
||
- 宽度/高度:8px
|
||
- 适合现代 UI 风格
|
||
- 不影响内容布局
|
||
|
||
### 使用方式
|
||
|
||
**1. 默认滚动条(自动应用)**
|
||
所有滚动容器都会自动使用主题滚动条样式。
|
||
|
||
**2. 隐藏滚动条**
|
||
如需隐藏滚动条但保持滚动功能:
|
||
|
||
```vue
|
||
<div class="scrollbar-hide">
|
||
<!-- 内容 -->
|
||
</div>
|
||
```
|
||
|
||
**3. 自定义滚动条颜色**
|
||
如需特定区域使用不同的滚动条颜色,可在组件样式中覆盖:
|
||
|
||
```scss
|
||
.my-custom-scroll {
|
||
&::-webkit-scrollbar-thumb {
|
||
background: var(--primary-color);
|
||
}
|
||
|
||
scrollbar-color: var(--primary-color) var(--background-secondary);
|
||
}
|
||
```
|
||
|
||
### 浏览器兼容性
|
||
- ✅ Chrome/Edge: 完美支持
|
||
- ✅ Firefox: 完美支持
|
||
- ✅ Safari: 完美支持
|
||
- ✅ Opera: 完美支持
|
||
- ⚠️ IE: 使用原生滚动条
|
||
|
||
## 📁 文件结构
|
||
|
||
```
|
||
front/
|
||
├── src/
|
||
│ ├── App.vue # 全局初始化主题系统 ⭐
|
||
│ ├── main.ts # 入口文件,引入样式
|
||
│ ├── assets/
|
||
│ │ └── css/
|
||
│ │ ├── root.scss # 主题变量定义
|
||
│ │ └── theme-usage.md # 详细使用文档
|
||
│ ├── utils/
|
||
│ │ └── theme.ts # 主题切换工具
|
||
│ ├── components/
|
||
│ │ └── ThemeToggle.vue # 主题切换组件
|
||
│ └── views/
|
||
│ └── components/
|
||
│ └── layout.vue # 已集成主题切换按钮
|
||
├── THEME_GUIDE.md # 本文件
|
||
```
|
||
|
||
## 💡 使用示例
|
||
|
||
### 示例 1: 基础组件
|
||
|
||
```vue
|
||
<template>
|
||
<div class="card">
|
||
<h3>{{ title }}</h3>
|
||
<p>{{ content }}</p>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
defineProps<{
|
||
title: string;
|
||
content: string;
|
||
}>();
|
||
</script>
|
||
|
||
<style scoped>
|
||
.card {
|
||
background: var(--card-bg);
|
||
color: var(--text-color);
|
||
padding: 20px;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--border-radius-lg);
|
||
box-shadow: var(--card-shadow);
|
||
transition: var(--transition-base);
|
||
}
|
||
|
||
.card:hover {
|
||
box-shadow: var(--shadow-lg);
|
||
border-color: var(--border-color-hover);
|
||
}
|
||
</style>
|
||
```
|
||
|
||
### 示例 2: 按钮组件
|
||
|
||
```vue
|
||
<template>
|
||
<button :class="buttonClass">
|
||
{{ text }}
|
||
</button>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
defineProps<{
|
||
type?: 'primary' | 'secondary' | 'danger';
|
||
text: string;
|
||
}>();
|
||
|
||
const buttonClass = computed(() => ({
|
||
'btn-primary': true,
|
||
[`btn-${props.type || 'primary'}`]: true,
|
||
}));
|
||
</script>
|
||
|
||
<style scoped>
|
||
button {
|
||
padding: 8px 16px;
|
||
border-radius: var(--border-radius);
|
||
border: none;
|
||
cursor: pointer;
|
||
transition: var(--transition-fast);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: var(--primary-color);
|
||
color: var(--text-inverse);
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: var(--primary-hover);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: var(--secondary-color);
|
||
color: var(--text-inverse);
|
||
}
|
||
|
||
.btn-danger {
|
||
background: var(--error-color);
|
||
color: var(--text-inverse);
|
||
}
|
||
</style>
|
||
```
|
||
|
||
### 示例 3: 状态提示
|
||
|
||
```vue
|
||
<template>
|
||
<div :class="['alert', `alert-${type}`]">
|
||
<i :class="iconClass"></i>
|
||
<span>{{ message }}</span>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
const props = defineProps<{
|
||
type: 'success' | 'warning' | 'error' | 'info';
|
||
message: string;
|
||
}>();
|
||
|
||
const iconClass = computed(() => {
|
||
const icons = {
|
||
success: 'fa-check-circle',
|
||
warning: 'fa-exclamation-triangle',
|
||
error: 'fa-times-circle',
|
||
info: 'fa-info-circle',
|
||
};
|
||
return `fas ${icons[props.type]}`;
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.alert {
|
||
padding: 12px 16px;
|
||
border-radius: var(--border-radius);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.alert-success {
|
||
color: var(--success-color);
|
||
background: var(--success-bg);
|
||
}
|
||
|
||
.alert-warning {
|
||
color: var(--warning-color);
|
||
background: var(--warning-bg);
|
||
}
|
||
|
||
.alert-error {
|
||
color: var(--error-color);
|
||
background: var(--error-bg);
|
||
}
|
||
|
||
.alert-info {
|
||
color: var(--info-color);
|
||
background: var(--info-bg);
|
||
}
|
||
</style>
|
||
```
|
||
|
||
## 🔧 API 参考
|
||
|
||
### ThemeManager 类
|
||
|
||
```typescript
|
||
class ThemeManager {
|
||
// 初始化主题
|
||
init(): void;
|
||
|
||
// 设置主题
|
||
setTheme(theme: 'light' | 'dark', save?: boolean): void;
|
||
|
||
// 切换主题
|
||
toggle(): ThemeMode;
|
||
|
||
// 获取当前主题
|
||
getCurrentTheme(): ThemeMode;
|
||
|
||
// 检查是否为暗色
|
||
isDark(): boolean;
|
||
|
||
// 检查是否为亮色
|
||
isLight(): boolean;
|
||
}
|
||
```
|
||
|
||
### useTheme Hook
|
||
|
||
```typescript
|
||
export const useTheme = () => {
|
||
return {
|
||
currentTheme: ThemeMode; // 当前主题
|
||
toggle(): void; // 切换主题
|
||
setTheme(theme: ThemeMode): void; // 设置主题
|
||
isDark(): boolean; // 是否暗色
|
||
isLight(): boolean; // 是否亮色
|
||
};
|
||
};
|
||
```
|
||
|
||
## 🎨 主题配色方案
|
||
|
||
### 亮色主题
|
||
- 背景: 白色 → 浅灰
|
||
- 文本: 深灰 → 黑色
|
||
- 主色: 蓝色系 (#3498db)
|
||
- 次色: 绿色系 (#2ecc71)
|
||
- 强调: 黄色系 (#ffcc00)
|
||
|
||
### 暗色主题
|
||
- 背景: 深灰 → 黑色
|
||
- 文本: 浅灰 → 白色
|
||
- 主色: 浅蓝系 (#5dade2)
|
||
- 次色: 浅绿系 (#58d68d)
|
||
- 强调: 浅黄系 (#f7dc6f)
|
||
|
||
## 📝 注意事项
|
||
|
||
1. **始终使用 CSS 变量**: 不要在样式中硬编码颜色值
|
||
2. **响应式绑定**: 在 Vue 组件中使用 `computed` 来响应式获取主题
|
||
3. **测试两个主题**: 确保在亮色和暗色主题下都有良好的可读性
|
||
4. **避免高对比度**: 暗色主题使用柔和的色彩,减少眼部疲劳
|
||
5. **合理使用阴影**: 暗色主题中使用更深的阴影增强层次感
|
||
|
||
## 🐛 故障排除
|
||
|
||
### 主题切换不生效
|
||
- 确保在组件中正确导入并使用 `useTheme()`
|
||
- 检查是否正确添加了 `root.scss` 到主样式文件
|
||
|
||
### 样式未应用
|
||
- 确保使用 CSS 变量而不是硬编码值
|
||
- 检查元素是否正确继承了主题变量
|
||
|
||
### TypeScript 错误
|
||
- 确保已正确导入类型定义
|
||
- 重启 VS Code 的 TypeScript 服务器
|
||
|
||
## 📞 支持
|
||
|
||
如有问题或建议,请查看:
|
||
- `front/src/assets/css/theme-usage.md` - 详细使用文档
|
||
- `front/src/utils/theme.ts` - 源代码和注释
|
||
- `front/src/components/ThemeToggle.vue` - 组件示例
|
||
|