根据配置改颜色
This commit is contained in:
parent
271a8368e5
commit
9720ee005a
@ -14,7 +14,7 @@
|
||||
width: 100px!important;
|
||||
height: 100px!important;
|
||||
border-radius: 50%;
|
||||
background: var(--theme-primary, #BA4A8F);
|
||||
background:black;
|
||||
padding: 5px!important;
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,24 @@
|
||||
$theme-primary: #BA4A8F;
|
||||
$theme-darker: #C1B2E5;
|
||||
$theme-dark: #DFD7F2;
|
||||
$basic-white: #FFFFFF;
|
||||
$basic-black: #000000;
|
||||
// 动态主题色配置
|
||||
// 这些SCSS变量现在会从CSS变量中获取值,支持动态主题切换
|
||||
|
||||
$text-disabled: #C3C3C3;
|
||||
$text-basic: #939393;
|
||||
$text-theme: #BA4A8F;
|
||||
$theme-primary: var(--theme-primary, #BA4A8F);
|
||||
$theme-darker: var(--theme-darker, #C1B2E5);
|
||||
$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;
|
||||
$btn-basic: #EEEAF7;
|
||||
$border-theme: var(--border-theme, #C1B2E5);
|
||||
|
||||
$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";
|
||||
|
||||
// 定义CSS自定义属性(CSS变量)
|
||||
// 注意:这些默认值会被JavaScript动态覆盖
|
||||
:root {
|
||||
--theme-primary: #{$theme-primary};
|
||||
--theme-darker: #{$theme-darker};
|
||||
--theme-dark: #{$theme-dark};
|
||||
--theme-success: #18a058;
|
||||
--theme-warning: #f0a020;
|
||||
--theme-error: #d03050;
|
||||
--theme-info: #2080f0;
|
||||
--basic-white: #{$basic-white};
|
||||
--basic-black: #{$basic-black};
|
||||
--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 {
|
||||
background-color: #e6fffb;
|
||||
color: #13c2c2;
|
||||
|
||||
}
|
||||
|
||||
.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__;
|
||||
}
|
46
src/main.js
46
src/main.js
@ -2,17 +2,39 @@ import router from "@/router/index.js";
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import { registerPlugins } from "./plugins/index.js";
|
||||
import { settingConfig } from "@/config/settings/index.js";
|
||||
window.process = {
|
||||
env: {
|
||||
VUE_APP_API_URL: import.meta.env.VITE_API_URL,
|
||||
},
|
||||
};
|
||||
import { initThemeSystem } from "@/config/theme/index.js";
|
||||
import store from "@/store/index.js";
|
||||
|
||||
// 动态设置CSS变量值
|
||||
document.documentElement.style.setProperty('--theme-primary', settingConfig.themeColor);
|
||||
// 异步初始化应用
|
||||
async function initApp() {
|
||||
window.process = {
|
||||
env: {
|
||||
VUE_APP_API_URL: import.meta.env.VITE_API_URL,
|
||||
},
|
||||
};
|
||||
|
||||
const app = createApp(App);
|
||||
// 注册插件
|
||||
registerPlugins(app);
|
||||
app.mount("#app");
|
||||
// 初始化主题系统(必须在创建应用之前)
|
||||
const currentTheme = await initThemeSystem();
|
||||
|
||||
// 更新store中的主题配置
|
||||
store.updateTheme(currentTheme.naiveUITheme);
|
||||
|
||||
// 监听主题变化事件
|
||||
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 VisitedViewAction from "./modules/visited-view";
|
||||
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 originState = {
|
||||
isCollapse: false,
|
||||
themeOverrides: {
|
||||
themeOverrides: getInitialTheme() || {
|
||||
// 默认主题配置(作为后备)
|
||||
DataTable: {
|
||||
sorterIconColor:'#fff',
|
||||
thColorHover: primaryColor,
|
||||
@ -48,6 +59,13 @@ const store = {
|
||||
changeDevice(device) {
|
||||
this.state.device = device;
|
||||
},
|
||||
|
||||
// 更新主题
|
||||
updateTheme(themeOverrides) {
|
||||
this.state.themeOverrides = themeOverrides;
|
||||
console.log('Store主题已更新:', themeOverrides);
|
||||
},
|
||||
|
||||
...VisitedViewAction
|
||||
};
|
||||
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