mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-22 13:05:18 +00:00
fix: 优化主题切换功能,实现即时生效和代码优化
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
import { useThemeStore } from "@/store/modules/theme.store";
|
||||
import { onMounted, onUnmounted } from "vue";
|
||||
import { onMounted, onUnmounted, computed } from "vue";
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
const theme = themeStore.theme;
|
||||
const themeVars = themeStore.themeVars;
|
||||
const theme = computed(() => themeStore.theme);
|
||||
const themeVars = computed(() => themeStore.themeVars);
|
||||
|
||||
// 监听主题变化事件
|
||||
const handleThemeChange = () => {
|
||||
const handleThemeChange = (newTheme: string) => {
|
||||
// 当主题变化时强制更新组件
|
||||
// 这里可以添加一些更新逻辑
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="app-container theme-adaptive">
|
||||
<view :key="renderKey" class="app-container theme-adaptive">
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-profile theme-card">
|
||||
<view class="blur-bg"></view>
|
||||
@@ -146,13 +146,16 @@ import { useToast } from "wot-design-uni";
|
||||
import { useRouter } from "uni-mini-router";
|
||||
import { useUserStore } from "@/store";
|
||||
import { useThemeStore } from "@/store/modules/theme.store";
|
||||
import { computed } from "vue";
|
||||
import { computed, ref, onMounted, onUnmounted } from "vue";
|
||||
|
||||
const toast = useToast();
|
||||
const userStore = useUserStore();
|
||||
const themeStore = useThemeStore();
|
||||
const themeVars = themeStore.themeVars;
|
||||
const currentThemeColor = themeStore.currentThemeColor;
|
||||
const themeVars = computed(() => themeStore.themeVars);
|
||||
const currentThemeColor = computed(() => themeStore.currentThemeColor);
|
||||
|
||||
// 强制重新渲染的key
|
||||
const renderKey = ref(0);
|
||||
|
||||
const userInfo = computed(() => userStore.userInfo);
|
||||
const isLogin = computed(() => !!userInfo.value);
|
||||
@@ -161,6 +164,19 @@ const isLoading = ref(false);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// 监听主题色变化
|
||||
const handleThemeColorChange = (color: string) => {
|
||||
renderKey.value++;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
uni.$on('global-theme-color-change', handleThemeColorChange);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('global-theme-color-change', handleThemeColorChange);
|
||||
});
|
||||
|
||||
// 登录
|
||||
const navigateToLoginPage = () => {
|
||||
const pages = getCurrentPages();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="app-container dark:text-[var(--wot-dark-color)]">
|
||||
<view :key="renderKey" class="app-container dark:text-[var(--wot-dark-color)]">
|
||||
<!-- 页面标题 -->
|
||||
<view class="page-header">
|
||||
<text class="page-title">主题设置</text>
|
||||
@@ -17,11 +17,14 @@
|
||||
<wd-card title="预设主题色">
|
||||
<!-- 预设颜色选择 -->
|
||||
<view class="color-section">
|
||||
<view class="color-grid">
|
||||
<view v-for="(color, index) in themeOptions" :key="index" class="color-item"
|
||||
:class="{ active: isActiveColor(color.primary) }" @click="selectColor(color)">
|
||||
<view :key="renderKey" class="color-grid">
|
||||
<view v-for="(color, index) in themeOptions"
|
||||
:key="`${index}-${renderKey}`"
|
||||
class="color-item"
|
||||
:class="{ active: isActiveColor(color) }"
|
||||
@click="selectColor(color)">
|
||||
<view class="color-preview" :style="{ backgroundColor: color.primary }">
|
||||
<wd-icon v-if="isActiveColor(color.primary)" name="check" size="20" color="#fff" />
|
||||
<wd-icon v-if="isActiveColor(color)" name="check" size="20" color="#fff" />
|
||||
</view>
|
||||
<text class="color-name">{{ color.name }}</text>
|
||||
</view>
|
||||
@@ -39,7 +42,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from "vue";
|
||||
import { computed, watch,ref } from "vue";
|
||||
import { useThemeStore } from "@/store/modules/theme.store";
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
@@ -51,9 +54,14 @@ const isDarkMode = computed({
|
||||
});
|
||||
const themeOptions = themeStore.themeColorOptions;
|
||||
|
||||
// 强制重新渲染的key
|
||||
const renderKey = ref(0);
|
||||
|
||||
// 检查颜色是否为当前选中颜色
|
||||
const isActiveColor = (color: string): boolean => {
|
||||
return themeStore.currentThemeColor.primary.toLowerCase() === color.toLowerCase();
|
||||
const isActiveColor = (color: typeof themeOptions[0]): boolean => {
|
||||
const currentColor = themeStore.currentThemeColor.primary.toLowerCase();
|
||||
const compareColor = color.primary.toLowerCase();
|
||||
return currentColor === compareColor;
|
||||
};
|
||||
|
||||
// 切换暗黑模式
|
||||
@@ -69,6 +77,10 @@ const handleToggleDarkMode = (value: boolean) => {
|
||||
// 选择主题色
|
||||
const selectColor = (color: typeof themeOptions[0]) => {
|
||||
themeStore.setCurrentThemeColor(color);
|
||||
|
||||
// 强制重新渲染所有组件
|
||||
renderKey.value++;
|
||||
|
||||
uni.showToast({ title: "主题色已更新", icon: "success", duration: 1000 });
|
||||
};
|
||||
|
||||
@@ -88,10 +100,23 @@ const resetTheme = () => {
|
||||
|
||||
// 监听主题变化,强制更新页面
|
||||
watch(() => themeStore.isDark, () => {
|
||||
// 触发页面重新渲染
|
||||
setTimeout(() => {
|
||||
// 强制更新页面
|
||||
}, 100);
|
||||
// 主题变化时强制重新渲染
|
||||
renderKey.value++;
|
||||
});
|
||||
|
||||
// 监听主题色变化
|
||||
watch(() => themeStore.currentThemeColor, () => {
|
||||
// 强制重新渲染以更新选中状态
|
||||
renderKey.value++;
|
||||
}, { deep: true });
|
||||
|
||||
// 监听主题色变量变化
|
||||
watch(() => themeStore.themeVars.colorTheme, () => {
|
||||
// 强制重新渲染以更新图标颜色
|
||||
renderKey.value++;
|
||||
|
||||
// 通知其他页面主题色已变化
|
||||
uni.$emit('global-theme-color-change', themeStore.themeVars.colorTheme);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -108,7 +133,7 @@ watch(() => themeStore.isDark, () => {
|
||||
padding: 40rpx 20rpx;
|
||||
margin-bottom: 30rpx;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, var(--wot-color-theme, #165dff) 0%, #667eea 100%);
|
||||
background: linear-gradient(135deg, var(--wot-color-theme, #4D7FFF) 0%, #667eea 100%);
|
||||
border-radius: 16rpx;
|
||||
|
||||
.page-title {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { useStorage } from "@uni-helper/uni-use";
|
||||
import type { ConfigProviderThemeVars } from "wot-design-uni";
|
||||
import { nextTick, reactive, computed } from "vue";
|
||||
import { nextTick, reactive, computed, watch } from "vue";
|
||||
|
||||
// 主题色选项接口
|
||||
export interface ThemeColorOption {
|
||||
@@ -29,8 +29,26 @@ export const useThemeStore = defineStore("appTheme", () => {
|
||||
// 主题色
|
||||
const currentThemeColor = useStorage<ThemeColorOption>("app-theme-color", themeColorOptions[0]);
|
||||
|
||||
// 获取当前主题的基础颜色配置
|
||||
const getThemeColors = (isDark: boolean) => ({
|
||||
// 基础颜色
|
||||
colorBg: isDark ? "#0f0f0f" : "#f8f8f8",
|
||||
colorTitle: isDark ? "#ffffff" : "#1d2129",
|
||||
colorContent: isDark ? "#e0e0e0" : "#4e5969",
|
||||
colorSecondary: isDark ? "#a0a0a0" : "#86909c",
|
||||
colorBorder: isDark ? "#2f2f2f" : "#e5e6eb",
|
||||
colorBorderLight: isDark ? "#3d3d3d" : "#f2f3f5",
|
||||
|
||||
// 卡片相关变量
|
||||
cardBg: isDark ? "#1a1a1a" : "#ffffff",
|
||||
cardTitleColor: isDark ? "#ffffff" : "#1d2129",
|
||||
cardContentColor: isDark ? "#e0e0e0" : "#4e5969",
|
||||
cardContentBorderColor: isDark ? "#2f2f2f" : "#e5e6eb",
|
||||
});
|
||||
|
||||
// 主题变量(响应式对象)
|
||||
const themeVars: ConfigProviderThemeVars = reactive({
|
||||
// 暗黑模式背景色
|
||||
darkBackground: "#0f0f0f",
|
||||
darkBackground2: "#1a1a1a",
|
||||
darkBackground3: "#242424",
|
||||
@@ -38,10 +56,19 @@ export const useThemeStore = defineStore("appTheme", () => {
|
||||
darkBackground5: "#3d3d3d",
|
||||
darkBackground6: "#4a4a4a",
|
||||
darkBackground7: "#606060",
|
||||
|
||||
// 暗黑模式文字颜色
|
||||
darkColor: "#ffffff",
|
||||
darkColor2: "#e0e0e0",
|
||||
darkColor3: "#a0a0a0",
|
||||
darkColorGray: "#a0a0a0",
|
||||
darkBorderColor: "#2f2f2f",
|
||||
|
||||
// 主题色
|
||||
colorTheme: currentThemeColor.value.primary,
|
||||
|
||||
// 根据当前主题模式设置基础颜色
|
||||
...getThemeColors(theme.value === 'dark'),
|
||||
});
|
||||
|
||||
// 计算属性
|
||||
@@ -49,30 +76,98 @@ export const useThemeStore = defineStore("appTheme", () => {
|
||||
|
||||
// 设置导航栏颜色
|
||||
const setNavigationBarColor = () => {
|
||||
console.log("设置导航栏颜色", theme.value);
|
||||
uni.setNavigationBarColor({
|
||||
frontColor: theme.value === "light" ? "#000000" : "#ffffff",
|
||||
backgroundColor: theme.value === "light" ? "#ffffff" : "#000000",
|
||||
});
|
||||
};
|
||||
|
||||
// 更新主题变量
|
||||
const updateThemeVars = () => {
|
||||
const isDark = theme.value === 'dark';
|
||||
const colors = getThemeColors(isDark);
|
||||
|
||||
// 更新所有主题变量
|
||||
Object.assign(themeVars, colors);
|
||||
};
|
||||
|
||||
// 获取主题CSS变量配置
|
||||
const getThemeCSSVariables = (isDark: boolean) => ({
|
||||
'--wot-color-bg': isDark ? '#0f0f0f' : '#f8f8f8',
|
||||
'--wot-color-title': isDark ? '#ffffff' : '#1d2129',
|
||||
'--wot-color-content': isDark ? '#e0e0e0' : '#4e5969',
|
||||
'--wot-color-secondary': isDark ? '#a0a0a0' : '#86909c',
|
||||
'--wot-color-border': isDark ? '#2f2f2f' : '#e5e6eb',
|
||||
'--wot-color-border-light': isDark ? '#3d3d3d' : '#f2f3f5',
|
||||
'--wot-card-bg': isDark ? '#1a1a1a' : '#ffffff',
|
||||
'--wot-card-content-border-color': isDark ? '#2f2f2f' : '#e5e6eb',
|
||||
});
|
||||
|
||||
// 更新CSS变量
|
||||
const updateCSSVariables = () => {
|
||||
if (typeof document !== 'undefined') {
|
||||
const root = document.documentElement;
|
||||
const isDark = theme.value === 'dark';
|
||||
|
||||
// 更新主题色
|
||||
root.style.setProperty('--wot-color-theme', currentThemeColor.value.primary);
|
||||
|
||||
// 更新主题类
|
||||
root.classList.toggle('dark', isDark);
|
||||
root.classList.toggle('light', !isDark);
|
||||
|
||||
// 批量设置CSS变量
|
||||
const cssVars = getThemeCSSVariables(isDark);
|
||||
Object.entries(cssVars).forEach(([key, value]) => {
|
||||
root.style.setProperty(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
// 更新主题变量
|
||||
updateThemeVars();
|
||||
};
|
||||
|
||||
// 切换主题, 指定主题模式,不传则自动切换
|
||||
const toggleTheme = (mode?: ThemeMode) => {
|
||||
theme.value = mode || (theme.value === "light" ? "dark" : "light");
|
||||
setNavigationBarColor();
|
||||
updateCSSVariables();
|
||||
|
||||
// 触发主题变化事件
|
||||
nextTick(() => {
|
||||
uni.$emit('theme-change', theme.value);
|
||||
});
|
||||
};
|
||||
|
||||
// 设置主题色
|
||||
const setCurrentThemeColor = (color: ThemeColorOption) => {
|
||||
currentThemeColor.value = color;
|
||||
themeVars.colorTheme = color.primary;
|
||||
console.log("主题色已设置:", color.name);
|
||||
|
||||
// 强制更新主题变量
|
||||
Object.assign(themeVars, {
|
||||
colorTheme: color.primary
|
||||
});
|
||||
|
||||
updateCSSVariables();
|
||||
|
||||
// 触发主题色变化事件
|
||||
nextTick(() => {
|
||||
uni.$emit('theme-color-change', color);
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化主题
|
||||
const initTheme = () => {
|
||||
// 更新主题变量中的颜色
|
||||
themeVars.colorTheme = currentThemeColor.value.primary;
|
||||
// 强制更新主题变量中的颜色
|
||||
Object.assign(themeVars, {
|
||||
colorTheme: currentThemeColor.value.primary
|
||||
});
|
||||
|
||||
// 更新主题变量
|
||||
updateThemeVars();
|
||||
|
||||
// 更新CSS变量
|
||||
updateCSSVariables();
|
||||
|
||||
// 设置导航栏颜色
|
||||
nextTick(() => {
|
||||
@@ -80,6 +175,19 @@ export const useThemeStore = defineStore("appTheme", () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 监听主题变化,自动更新CSS变量
|
||||
watch(theme, () => {
|
||||
updateCSSVariables();
|
||||
});
|
||||
|
||||
// 监听主题色变化,自动更新CSS变量
|
||||
watch(currentThemeColor, () => {
|
||||
Object.assign(themeVars, {
|
||||
colorTheme: currentThemeColor.value.primary
|
||||
});
|
||||
updateCSSVariables();
|
||||
});
|
||||
|
||||
// 注意:全局主题管理已在App.vue中处理
|
||||
// 包括:系统主题监听、导航栏颜色同步等
|
||||
// 组件中一般不需要再调用initTheme(),除非有特殊需求
|
||||
|
||||
Reference in New Issue
Block a user