根据配置改颜色
This commit is contained in:
parent
271a8368e5
commit
9720ee005a
@ -14,7 +14,7 @@
|
|||||||
width: 100px!important;
|
width: 100px!important;
|
||||||
height: 100px!important;
|
height: 100px!important;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--theme-primary, #BA4A8F);
|
background:black;
|
||||||
padding: 5px!important;
|
padding: 5px!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
$theme-primary: #BA4A8F;
|
// 动态主题色配置
|
||||||
$theme-darker: #C1B2E5;
|
// 这些SCSS变量现在会从CSS变量中获取值,支持动态主题切换
|
||||||
$theme-dark: #DFD7F2;
|
|
||||||
$basic-white: #FFFFFF;
|
|
||||||
$basic-black: #000000;
|
|
||||||
|
|
||||||
$text-disabled: #C3C3C3;
|
$theme-primary: var(--theme-primary, #BA4A8F);
|
||||||
$text-basic: #939393;
|
$theme-darker: var(--theme-darker, #C1B2E5);
|
||||||
$text-theme: #BA4A8F;
|
$theme-dark: var(--theme-dark, #DFD7F2);
|
||||||
|
$theme-success: var(--theme-success, #18a058);
|
||||||
|
$theme-warning: var(--theme-warning, #f0a020);
|
||||||
|
$theme-error: var(--theme-error, #d03050);
|
||||||
|
$theme-info: var(--theme-info, #2080f0);
|
||||||
|
|
||||||
$border-theme: #C1B2E5;
|
$basic-white: var(--basic-white, #FFFFFF);
|
||||||
|
$basic-black: var(--basic-black, #000000);
|
||||||
|
|
||||||
$input-bg: #777777;
|
$text-disabled: var(--text-disabled, #C3C3C3);
|
||||||
|
$text-basic: var(--text-basic, #939393);
|
||||||
|
$text-theme: var(--text-theme, #BA4A8F);
|
||||||
|
|
||||||
$btn-primary: #BA4A8F;
|
$border-theme: var(--border-theme, #C1B2E5);
|
||||||
$btn-basic: #EEEAF7;
|
|
||||||
|
$input-bg: var(--input-bg, #777777);
|
||||||
|
|
||||||
|
$btn-primary: var(--btn-primary, #BA4A8F);
|
||||||
|
$btn-basic: var(--btn-basic, #EEEAF7);
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
@import "color.scss";
|
@import "color.scss";
|
||||||
|
|
||||||
// 定义CSS自定义属性(CSS变量)
|
// 定义CSS自定义属性(CSS变量)
|
||||||
|
// 注意:这些默认值会被JavaScript动态覆盖
|
||||||
:root {
|
:root {
|
||||||
--theme-primary: #{$theme-primary};
|
--theme-primary: #{$theme-primary};
|
||||||
--theme-darker: #{$theme-darker};
|
--theme-darker: #{$theme-darker};
|
||||||
--theme-dark: #{$theme-dark};
|
--theme-dark: #{$theme-dark};
|
||||||
|
--theme-success: #18a058;
|
||||||
|
--theme-warning: #f0a020;
|
||||||
|
--theme-error: #d03050;
|
||||||
|
--theme-info: #2080f0;
|
||||||
--basic-white: #{$basic-white};
|
--basic-white: #{$basic-white};
|
||||||
--basic-black: #{$basic-black};
|
--basic-black: #{$basic-black};
|
||||||
--text-theme: #{$text-theme};
|
--text-theme: #{$text-theme};
|
||||||
|
92
src/components/ThemeSwitch.vue
Normal file
92
src/components/ThemeSwitch.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div class="theme-switch">
|
||||||
|
<n-select
|
||||||
|
v-model:value="selectedTheme"
|
||||||
|
:options="themeOptions"
|
||||||
|
@update:value="handleThemeChange"
|
||||||
|
placeholder="选择主题"
|
||||||
|
style="width: 200px"
|
||||||
|
>
|
||||||
|
<template #option="{ node, option }">
|
||||||
|
<div class="theme-option">
|
||||||
|
<div
|
||||||
|
class="theme-color-preview"
|
||||||
|
:style="{ backgroundColor: option.color }"
|
||||||
|
></div>
|
||||||
|
<span>{{ option.label }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</n-select>
|
||||||
|
|
||||||
|
<!-- 当前主题信息 -->
|
||||||
|
<div v-if="currentTheme" class="current-theme-info">
|
||||||
|
<small>当前主题: {{ currentTheme.config.name }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from 'vue';
|
||||||
|
import { NSelect } from 'naive-ui';
|
||||||
|
import { switchTheme, getCurrentTheme, getAllThemes, onThemeChange } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const selectedTheme = ref('');
|
||||||
|
const currentTheme = ref(null);
|
||||||
|
|
||||||
|
// 主题选项
|
||||||
|
const themeOptions = computed(() => {
|
||||||
|
const themes = getAllThemes();
|
||||||
|
return Object.entries(themes).map(([key, config]) => ({
|
||||||
|
label: config.name,
|
||||||
|
value: key,
|
||||||
|
color: config.primary
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理主题切换
|
||||||
|
const handleThemeChange = async (themeKey) => {
|
||||||
|
if (themeKey) {
|
||||||
|
await switchTheme(themeKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听主题变化
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始化当前主题
|
||||||
|
currentTheme.value = getCurrentTheme();
|
||||||
|
selectedTheme.value = currentTheme.value?.key || 'default';
|
||||||
|
|
||||||
|
// 监听主题变化事件
|
||||||
|
onThemeChange((themeInfo) => {
|
||||||
|
currentTheme.value = getCurrentTheme();
|
||||||
|
selectedTheme.value = themeInfo.key;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.theme-switch {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-color-preview {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-theme-info {
|
||||||
|
color: var(--theme-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1518,7 +1518,7 @@ const numWidth = computed(() => {
|
|||||||
|
|
||||||
.x-upload-download-button:hover {
|
.x-upload-download-button:hover {
|
||||||
background-color: #e6fffb;
|
background-color: #e6fffb;
|
||||||
color: #13c2c2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.x-upload-delete-button:hover {
|
.x-upload-delete-button:hover {
|
||||||
|
177
src/config/theme/README.md
Normal file
177
src/config/theme/README.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
# 主题系统使用文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
这个主题系统可以根据网站URL自动切换主题色,支持多环境和多品牌的主题配置。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- 🎨 基于URL自动切换主题
|
||||||
|
- 🔄 支持运行时动态切换主题
|
||||||
|
- 🎯 同时更新CSS变量和UI框架主题
|
||||||
|
- 📱 支持多环境配置(开发、测试、生产)
|
||||||
|
- 🛠️ 提供完整的工具函数和组件
|
||||||
|
|
||||||
|
## 配置文件
|
||||||
|
|
||||||
|
### 主题配置 (`src/config/theme/index.js`)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export const themeConfigs = {
|
||||||
|
default: {
|
||||||
|
name: '体制外主题',
|
||||||
|
primary: '#BA4A8F',
|
||||||
|
// ... 其他颜色
|
||||||
|
},
|
||||||
|
main: {
|
||||||
|
name: '体制内主题',
|
||||||
|
primary: '#1890FF',
|
||||||
|
// ... 其他颜色
|
||||||
|
}
|
||||||
|
// ... 更多主题
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### URL映射规则
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export const urlThemeMapping = {
|
||||||
|
'main': ['main.fontree.com', 'fontree-main.com'],
|
||||||
|
'default': ['fontree.com', 'www.fontree.com'],
|
||||||
|
'test': ['test.fontree.com', 'staging'],
|
||||||
|
'dev': ['localhost', '127.0.0.1']
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 自动主题切换
|
||||||
|
|
||||||
|
系统会在应用启动时自动检测URL并应用相应主题,无需手动配置。
|
||||||
|
|
||||||
|
### 2. 手动切换主题
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { switchTheme } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
// 切换到指定主题
|
||||||
|
switchTheme('main'); // 切换到体制内主题
|
||||||
|
switchTheme('test'); // 切换到测试主题
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 在Vue组件中使用
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p>当前主题: {{ currentTheme?.config.name }}</p>
|
||||||
|
<button @click="switchTheme('main')">切换到体制内主题</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useTheme } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
const { currentTheme, switchTheme } = useTheme();
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 使用主题切换组件
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<ThemeSwitch />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import ThemeSwitch from '@/components/ThemeSwitch.vue';
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 在CSS中使用主题变量
|
||||||
|
|
||||||
|
```css
|
||||||
|
.my-component {
|
||||||
|
background-color: var(--theme-primary);
|
||||||
|
color: var(--theme-success);
|
||||||
|
border: 1px solid var(--theme-darker);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 监听主题变化
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { onThemeChange } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
// 监听主题变化
|
||||||
|
const unsubscribe = onThemeChange((themeInfo) => {
|
||||||
|
console.log('主题已切换:', themeInfo.key, themeInfo.config);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 取消监听
|
||||||
|
unsubscribe();
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSS变量列表
|
||||||
|
|
||||||
|
系统会自动设置以下CSS变量:
|
||||||
|
|
||||||
|
- `--theme-primary`: 主题主色
|
||||||
|
- `--theme-darker`: 主题深色
|
||||||
|
- `--theme-dark`: 主题更深色
|
||||||
|
- `--theme-success`: 成功色
|
||||||
|
- `--theme-warning`: 警告色
|
||||||
|
- `--theme-error`: 错误色
|
||||||
|
- `--theme-info`: 信息色
|
||||||
|
|
||||||
|
## 添加新主题
|
||||||
|
|
||||||
|
1. 在 `themeConfigs` 中添加新主题配置
|
||||||
|
2. 在 `urlThemeMapping` 中添加URL匹配规则
|
||||||
|
3. 重启应用即可生效
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 添加新主题
|
||||||
|
export const themeConfigs = {
|
||||||
|
// ... 现有主题
|
||||||
|
custom: {
|
||||||
|
name: '自定义主题',
|
||||||
|
primary: '#FF6B35',
|
||||||
|
darker: '#FF8C69',
|
||||||
|
// ... 其他颜色
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加URL映射
|
||||||
|
export const urlThemeMapping = {
|
||||||
|
// ... 现有映射
|
||||||
|
'custom': ['custom.fontree.com', 'my-custom-domain.com']
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 调试和测试
|
||||||
|
|
||||||
|
在浏览器控制台中可以看到主题切换的日志信息:
|
||||||
|
|
||||||
|
```
|
||||||
|
当前URL: http://localhost:3000
|
||||||
|
当前hostname: localhost
|
||||||
|
匹配到主题: dev (开发环境主题)
|
||||||
|
CSS变量已更新: {primary: "#13C2C2", ...}
|
||||||
|
主题系统初始化完成: {...}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 主题系统会在应用启动时自动初始化
|
||||||
|
2. URL匹配是模糊匹配,会检查hostname和完整URL
|
||||||
|
3. 如果没有匹配到任何规则,会使用默认主题
|
||||||
|
4. 主题切换会同时更新CSS变量和UI框架配置
|
||||||
|
5. 所有主题变化都会触发 `themeChanged` 事件
|
||||||
|
|
||||||
|
## 扩展功能
|
||||||
|
|
||||||
|
- 可以添加主题持久化存储
|
||||||
|
- 可以添加主题预览功能
|
||||||
|
- 可以集成用户偏好设置
|
||||||
|
- 可以添加主题动画过渡效果
|
98
src/config/theme/colors.js
Normal file
98
src/config/theme/colors.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* 动态颜色配置
|
||||||
|
* 统一管理所有颜色变量,支持主题切换
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { themeConfigs } from './index.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前主题的颜色配置
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
* @returns {Object} 颜色配置对象
|
||||||
|
*/
|
||||||
|
export function getThemeColors(themeKey = 'default') {
|
||||||
|
const theme = themeConfigs[themeKey] || themeConfigs.default;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// 主题色系
|
||||||
|
'theme-primary': theme.primary,
|
||||||
|
'theme-darker': theme.darker,
|
||||||
|
'theme-dark': theme.dark,
|
||||||
|
'theme-success': theme.success,
|
||||||
|
'theme-warning': theme.warning,
|
||||||
|
'theme-error': theme.error,
|
||||||
|
'theme-info': theme.info,
|
||||||
|
|
||||||
|
// 基础色系
|
||||||
|
'basic-white': '#FFFFFF',
|
||||||
|
'basic-black': '#000000',
|
||||||
|
|
||||||
|
// 文本色系
|
||||||
|
'text-disabled': '#C3C3C3',
|
||||||
|
'text-basic': '#939393',
|
||||||
|
'text-theme': theme.primary,
|
||||||
|
|
||||||
|
// 边框色系
|
||||||
|
'border-theme': theme.darker,
|
||||||
|
|
||||||
|
// 输入框色系
|
||||||
|
'input-bg': '#777777',
|
||||||
|
|
||||||
|
// 按钮色系
|
||||||
|
'btn-primary': theme.primary,
|
||||||
|
'btn-basic': '#EEEAF7'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成CSS变量字符串
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
* @returns {string} CSS变量定义字符串
|
||||||
|
*/
|
||||||
|
export function generateCSSVariables(themeKey = 'default') {
|
||||||
|
const colors = getThemeColors(themeKey);
|
||||||
|
|
||||||
|
let cssVars = ':root {\n';
|
||||||
|
|
||||||
|
Object.entries(colors).forEach(([key, value]) => {
|
||||||
|
cssVars += ` --${key}: ${value};\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
cssVars += '}\n';
|
||||||
|
|
||||||
|
return cssVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成SCSS变量字符串
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
* @returns {string} SCSS变量定义字符串
|
||||||
|
*/
|
||||||
|
export function generateSCSSVariables(themeKey = 'default') {
|
||||||
|
const colors = getThemeColors(themeKey);
|
||||||
|
|
||||||
|
let scssVars = '// 动态生成的SCSS变量 - 请勿手动修改\n';
|
||||||
|
scssVars += `// 当前主题: ${themeConfigs[themeKey]?.name || '默认主题'}\n\n`;
|
||||||
|
|
||||||
|
Object.entries(colors).forEach(([key, value]) => {
|
||||||
|
const scssKey = key.replace(/-/g, '-'); // 保持连字符格式
|
||||||
|
scssVars += `$${scssKey}: ${value};\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return scssVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用颜色到DOM
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
*/
|
||||||
|
export function applyColorsToDOM(themeKey = 'default') {
|
||||||
|
const colors = getThemeColors(themeKey);
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
Object.entries(colors).forEach(([key, value]) => {
|
||||||
|
root.style.setProperty(`--${key}`, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('颜色已应用到DOM:', colors);
|
||||||
|
}
|
225
src/config/theme/index.js
Normal file
225
src/config/theme/index.js
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/**
|
||||||
|
* 基于URL的主题配置系统
|
||||||
|
* 根据网站URL自动切换主题色
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 主题配置映射表
|
||||||
|
export const themeConfigs = {
|
||||||
|
// 默认主题(体制外)
|
||||||
|
default: {
|
||||||
|
name: '体制外主题',
|
||||||
|
primary: '#BA4A8F',
|
||||||
|
darker: '#C1B2E5',
|
||||||
|
dark: '#DFD7F2',
|
||||||
|
success: '#18a058',
|
||||||
|
warning: '#f0a020',
|
||||||
|
error: '#d03050',
|
||||||
|
info: '#2080f0'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 体制内主题
|
||||||
|
main: {
|
||||||
|
name: '体制内主题',
|
||||||
|
primary: '#1890FF',
|
||||||
|
darker: '#40A9FF',
|
||||||
|
dark: '#91D5FF',
|
||||||
|
success: '#52c41a',
|
||||||
|
warning: '#faad14',
|
||||||
|
error: '#f5222d',
|
||||||
|
info: '#1890ff'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 测试环境主题
|
||||||
|
test: {
|
||||||
|
name: '测试环境主题',
|
||||||
|
primary: '#722ED1',
|
||||||
|
darker: '#B37FEB',
|
||||||
|
dark: '#D3ADF7',
|
||||||
|
success: '#52c41a',
|
||||||
|
warning: '#fa8c16',
|
||||||
|
error: '#f5222d',
|
||||||
|
info: '#722ed1'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开发环境主题
|
||||||
|
dev: {
|
||||||
|
name: '开发环境主题',
|
||||||
|
primary: '#BA4A8F',
|
||||||
|
darker: '#BA4A8F',
|
||||||
|
dark: '#BA4A8F',
|
||||||
|
success: '#52c41a',
|
||||||
|
warning: '#faad14',
|
||||||
|
error: '#f5222d',
|
||||||
|
info: '#BA4A8F '
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// URL匹配规则
|
||||||
|
export const urlThemeMapping = {
|
||||||
|
// 生产环境 - 体制内
|
||||||
|
'main': ['main.fontree.com', 'fontree-main.com', 'main-fontree'],
|
||||||
|
|
||||||
|
// 生产环境 - 体制外(默认)
|
||||||
|
'default': ['fontree.com', 'www.fontree.com', 'app.fontree.com'],
|
||||||
|
|
||||||
|
// 测试环境
|
||||||
|
'test': ['127.0.0.1', 'fontree-test.com', 'test-fontree', 'staging'],
|
||||||
|
|
||||||
|
// 开发环境
|
||||||
|
'dev': ['localhost', '127.2.0.1', 'dev.fontree.com', 'fontree-dev.com', 'dev-fontree']
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据当前URL获取主题配置
|
||||||
|
* @returns {Object} 主题配置对象
|
||||||
|
*/
|
||||||
|
export function getThemeByUrl() {
|
||||||
|
const hostname = window.location.hostname;
|
||||||
|
const href = window.location.href;
|
||||||
|
|
||||||
|
console.log('当前URL:', href);
|
||||||
|
console.log('当前hostname:', hostname);
|
||||||
|
|
||||||
|
// 遍历URL映射规则
|
||||||
|
for (const [themeKey, patterns] of Object.entries(urlThemeMapping)) {
|
||||||
|
for (const pattern of patterns) {
|
||||||
|
if (hostname.includes(pattern) || href.includes(pattern)) {
|
||||||
|
console.log(`匹配到主题: ${themeKey} (${themeConfigs[themeKey].name})`);
|
||||||
|
return {
|
||||||
|
key: themeKey,
|
||||||
|
config: themeConfigs[themeKey]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认返回体制外主题
|
||||||
|
console.log('使用默认主题');
|
||||||
|
return {
|
||||||
|
key: 'default',
|
||||||
|
config: themeConfigs.default
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用主题到CSS变量
|
||||||
|
* @param {Object} themeConfig 主题配置
|
||||||
|
*/
|
||||||
|
export async function applyThemeToCSS(themeConfig) {
|
||||||
|
// 使用新的颜色配置系统
|
||||||
|
const { applyColorsToDOM } = await import('./colors.js');
|
||||||
|
|
||||||
|
// 根据主题配置找到对应的主题键名
|
||||||
|
const themeKey = Object.keys(themeConfigs).find(key =>
|
||||||
|
themeConfigs[key].primary === themeConfig.primary
|
||||||
|
) || 'default';
|
||||||
|
|
||||||
|
// 应用所有颜色到DOM
|
||||||
|
applyColorsToDOM(themeKey);
|
||||||
|
|
||||||
|
console.log('CSS变量已更新:', themeConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成Naive UI主题配置
|
||||||
|
* @param {Object} themeConfig 主题配置
|
||||||
|
* @returns {Object} Naive UI主题覆盖配置
|
||||||
|
*/
|
||||||
|
export function generateNaiveUITheme(themeConfig) {
|
||||||
|
return {
|
||||||
|
common: {
|
||||||
|
primaryColor: themeConfig.primary,
|
||||||
|
primaryColorHover: themeConfig.darker,
|
||||||
|
primaryColorPressed: themeConfig.primary,
|
||||||
|
primaryColorSuppl: themeConfig.primary,
|
||||||
|
successColor: themeConfig.success,
|
||||||
|
warningColor: themeConfig.warning,
|
||||||
|
errorColor: themeConfig.error,
|
||||||
|
infoColor: themeConfig.info
|
||||||
|
},
|
||||||
|
Button: {
|
||||||
|
// Primary按钮的颜色配置
|
||||||
|
colorPrimary: themeConfig.primary,
|
||||||
|
colorHoverPrimary: themeConfig.darker,
|
||||||
|
colorPressedPrimary: themeConfig.primary,
|
||||||
|
colorFocusPrimary: themeConfig.primary,
|
||||||
|
|
||||||
|
// Tertiary按钮的颜色配置
|
||||||
|
textColor: themeConfig.primary,
|
||||||
|
textColorHover: themeConfig.darker,
|
||||||
|
textColorPressed: themeConfig.primary,
|
||||||
|
textColorFocus: themeConfig.primary,
|
||||||
|
textColorDisabled: '#c0c4cc',
|
||||||
|
|
||||||
|
// 边框颜色
|
||||||
|
borderPrimary: themeConfig.primary,
|
||||||
|
borderHoverPrimary: themeConfig.darker,
|
||||||
|
borderPressedPrimary: themeConfig.primary,
|
||||||
|
borderFocusPrimary: themeConfig.primary,
|
||||||
|
|
||||||
|
// 波纹效果颜色
|
||||||
|
rippleColorPrimary: `${themeConfig.primary}1a`
|
||||||
|
},
|
||||||
|
DataTable: {
|
||||||
|
thColor: themeConfig.primary,
|
||||||
|
thColorHover: themeConfig.darker,
|
||||||
|
thTextColor: '#fff',
|
||||||
|
itemColorActive: themeConfig.primary,
|
||||||
|
sorterIconColor: '#fff'
|
||||||
|
},
|
||||||
|
Input: {
|
||||||
|
borderHover: themeConfig.primary,
|
||||||
|
borderFocus: themeConfig.primary,
|
||||||
|
boxShadowFocus: `0 0 0 2px ${themeConfig.primary}1a`
|
||||||
|
},
|
||||||
|
Select: {
|
||||||
|
peers: {
|
||||||
|
InternalSelection: {
|
||||||
|
borderHover: themeConfig.primary,
|
||||||
|
borderFocus: themeConfig.primary,
|
||||||
|
boxShadowFocus: `0 0 0 2px ${themeConfig.primary}1a`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 添加更多组件的主题配置
|
||||||
|
Checkbox: {
|
||||||
|
colorChecked: themeConfig.primary,
|
||||||
|
colorCheckedHover: themeConfig.darker,
|
||||||
|
colorCheckedPressed: themeConfig.primary
|
||||||
|
},
|
||||||
|
Radio: {
|
||||||
|
colorActive: themeConfig.primary,
|
||||||
|
colorActiveHover: themeConfig.darker
|
||||||
|
},
|
||||||
|
Switch: {
|
||||||
|
railColorActive: themeConfig.primary,
|
||||||
|
railColorActiveHover: themeConfig.darker
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化主题系统
|
||||||
|
*/
|
||||||
|
export async function initThemeSystem() {
|
||||||
|
const { key, config } = getThemeByUrl();
|
||||||
|
|
||||||
|
// 应用CSS变量
|
||||||
|
await applyThemeToCSS(config);
|
||||||
|
|
||||||
|
// 存储当前主题信息到全局
|
||||||
|
window.__CURRENT_THEME__ = {
|
||||||
|
key,
|
||||||
|
config,
|
||||||
|
naiveUITheme: generateNaiveUITheme(config)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 触发自定义事件,通知其他组件主题已更新
|
||||||
|
window.dispatchEvent(new CustomEvent('themeChanged', {
|
||||||
|
detail: { key, config }
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log('主题系统初始化完成:', window.__CURRENT_THEME__);
|
||||||
|
|
||||||
|
return window.__CURRENT_THEME__;
|
||||||
|
}
|
40
src/main.js
40
src/main.js
@ -2,17 +2,39 @@ import router from "@/router/index.js";
|
|||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import { registerPlugins } from "./plugins/index.js";
|
import { registerPlugins } from "./plugins/index.js";
|
||||||
import { settingConfig } from "@/config/settings/index.js";
|
import { initThemeSystem } from "@/config/theme/index.js";
|
||||||
window.process = {
|
import store from "@/store/index.js";
|
||||||
|
|
||||||
|
// 异步初始化应用
|
||||||
|
async function initApp() {
|
||||||
|
window.process = {
|
||||||
env: {
|
env: {
|
||||||
VUE_APP_API_URL: import.meta.env.VITE_API_URL,
|
VUE_APP_API_URL: import.meta.env.VITE_API_URL,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 动态设置CSS变量值
|
// 初始化主题系统(必须在创建应用之前)
|
||||||
document.documentElement.style.setProperty('--theme-primary', settingConfig.themeColor);
|
const currentTheme = await initThemeSystem();
|
||||||
|
|
||||||
const app = createApp(App);
|
// 更新store中的主题配置
|
||||||
// 注册插件
|
store.updateTheme(currentTheme.naiveUITheme);
|
||||||
registerPlugins(app);
|
|
||||||
app.mount("#app");
|
// 监听主题变化事件
|
||||||
|
window.addEventListener('themeChanged', (event) => {
|
||||||
|
const { key, config } = event.detail;
|
||||||
|
console.log('主题已切换:', key, config);
|
||||||
|
|
||||||
|
// 更新store中的主题
|
||||||
|
if (window.__CURRENT_THEME__) {
|
||||||
|
store.updateTheme(window.__CURRENT_THEME__.naiveUITheme);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const app = createApp(App);
|
||||||
|
// 注册插件
|
||||||
|
registerPlugins(app);
|
||||||
|
app.mount("#app");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动应用
|
||||||
|
initApp().catch(console.error);
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
import { reactive } from "vue";
|
import { reactive } from "vue";
|
||||||
import VisitedViewAction from "./modules/visited-view";
|
import VisitedViewAction from "./modules/visited-view";
|
||||||
import { settingConfig } from "@/config/settings/index.js";
|
import { settingConfig } from "@/config/settings/index.js";
|
||||||
|
import { generateNaiveUITheme } from "@/config/theme/index.js";
|
||||||
|
|
||||||
|
// 获取初始主题色(如果主题系统还未初始化,使用默认值)
|
||||||
|
const getInitialTheme = () => {
|
||||||
|
if (window.__CURRENT_THEME__) {
|
||||||
|
return generateNaiveUITheme(window.__CURRENT_THEME__.config);
|
||||||
|
}
|
||||||
|
return null; // 将在main.js中初始化后更新
|
||||||
|
};
|
||||||
|
|
||||||
const primaryColor = settingConfig.themeColor;
|
const primaryColor = settingConfig.themeColor;
|
||||||
const originState = {
|
const originState = {
|
||||||
isCollapse: false,
|
isCollapse: false,
|
||||||
themeOverrides: {
|
themeOverrides: getInitialTheme() || {
|
||||||
|
// 默认主题配置(作为后备)
|
||||||
DataTable: {
|
DataTable: {
|
||||||
sorterIconColor:'#fff',
|
sorterIconColor:'#fff',
|
||||||
thColorHover: primaryColor,
|
thColorHover: primaryColor,
|
||||||
@ -48,6 +59,13 @@ const store = {
|
|||||||
changeDevice(device) {
|
changeDevice(device) {
|
||||||
this.state.device = device;
|
this.state.device = device;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 更新主题
|
||||||
|
updateTheme(themeOverrides) {
|
||||||
|
this.state.themeOverrides = themeOverrides;
|
||||||
|
console.log('Store主题已更新:', themeOverrides);
|
||||||
|
},
|
||||||
|
|
||||||
...VisitedViewAction
|
...VisitedViewAction
|
||||||
};
|
};
|
||||||
export default store;
|
export default store;
|
||||||
|
136
src/utils/theme.js
Normal file
136
src/utils/theme.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* 主题工具函数
|
||||||
|
* 提供主题切换和管理的实用工具
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { applyThemeToCSS, generateNaiveUITheme, themeConfigs } from "@/config/theme/index.js";
|
||||||
|
import store from "@/store/index.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动切换主题
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
*/
|
||||||
|
export async function switchTheme(themeKey) {
|
||||||
|
if (!themeConfigs[themeKey]) {
|
||||||
|
console.error('主题不存在:', themeKey);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = themeConfigs[themeKey];
|
||||||
|
|
||||||
|
// 应用CSS变量
|
||||||
|
await applyThemeToCSS(config);
|
||||||
|
|
||||||
|
// 生成并应用UI框架主题
|
||||||
|
const naiveUITheme = generateNaiveUITheme(config);
|
||||||
|
store.updateTheme(naiveUITheme);
|
||||||
|
|
||||||
|
// 更新全局主题信息
|
||||||
|
window.__CURRENT_THEME__ = {
|
||||||
|
key: themeKey,
|
||||||
|
config,
|
||||||
|
naiveUITheme
|
||||||
|
};
|
||||||
|
|
||||||
|
// 强制刷新页面样式(确保所有组件都能应用新主题)
|
||||||
|
document.documentElement.style.display = 'none';
|
||||||
|
setTimeout(() => {
|
||||||
|
document.documentElement.style.display = '';
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// 触发主题变化事件
|
||||||
|
window.dispatchEvent(new CustomEvent('themeChanged', {
|
||||||
|
detail: { key: themeKey, config }
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log('手动切换主题成功:', themeKey, config);
|
||||||
|
console.log('应用的Naive UI主题:', naiveUITheme);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前主题信息
|
||||||
|
* @returns {Object} 当前主题信息
|
||||||
|
*/
|
||||||
|
export function getCurrentTheme() {
|
||||||
|
return window.__CURRENT_THEME__ || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有可用主题
|
||||||
|
* @returns {Object} 所有主题配置
|
||||||
|
*/
|
||||||
|
export function getAllThemes() {
|
||||||
|
return themeConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据颜色值获取对比色(用于文本颜色)
|
||||||
|
* @param {string} hexColor 十六进制颜色值
|
||||||
|
* @returns {string} 对比色(黑色或白色)
|
||||||
|
*/
|
||||||
|
export function getContrastColor(hexColor) {
|
||||||
|
// 移除#号
|
||||||
|
const hex = hexColor.replace('#', '');
|
||||||
|
|
||||||
|
// 转换为RGB
|
||||||
|
const r = parseInt(hex.substr(0, 2), 16);
|
||||||
|
const g = parseInt(hex.substr(2, 2), 16);
|
||||||
|
const b = parseInt(hex.substr(4, 2), 16);
|
||||||
|
|
||||||
|
// 计算亮度
|
||||||
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||||
|
|
||||||
|
// 返回对比色
|
||||||
|
return brightness > 128 ? '#000000' : '#ffffff';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成主题色的变体(浅色、深色等)
|
||||||
|
* @param {string} baseColor 基础颜色
|
||||||
|
* @returns {Object} 颜色变体
|
||||||
|
*/
|
||||||
|
export function generateColorVariants(baseColor) {
|
||||||
|
// 这里可以实现颜色变体生成算法
|
||||||
|
// 简单示例:
|
||||||
|
return {
|
||||||
|
base: baseColor,
|
||||||
|
light: baseColor + '40', // 添加透明度
|
||||||
|
lighter: baseColor + '20',
|
||||||
|
dark: baseColor,
|
||||||
|
darker: baseColor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听主题变化
|
||||||
|
* @param {Function} callback 回调函数
|
||||||
|
* @returns {Function} 取消监听的函数
|
||||||
|
*/
|
||||||
|
export function onThemeChange(callback) {
|
||||||
|
const handler = (event) => {
|
||||||
|
callback(event.detail);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('themeChanged', handler);
|
||||||
|
|
||||||
|
// 返回取消监听的函数
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('themeChanged', handler);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建主题切换的Vue组合式函数
|
||||||
|
* @returns {Object} 主题相关的响应式数据和方法
|
||||||
|
*/
|
||||||
|
export function useTheme() {
|
||||||
|
const currentTheme = getCurrentTheme();
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentTheme,
|
||||||
|
switchTheme,
|
||||||
|
getAllThemes,
|
||||||
|
onThemeChange
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user