fix: 优化主题切换功能,实现即时生效和代码优化

This commit is contained in:
Guo Tiantian
2025-09-09 21:49:03 +08:00
parent 8bb5134cb2
commit 3d4a8fd7b0
6 changed files with 178 additions and 31 deletions
+4 -4
View File
@@ -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) => {
// 当主题变化时强制更新组件
// 这里可以添加一些更新逻辑
};
+20 -4
View File
@@ -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();
+38 -13
View File
@@ -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 {
+114 -6
View File
@@ -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(),除非有特殊需求