From 3bdc3e2dfe4f71fb863b5bb5f77c7275cec631e9 Mon Sep 17 00:00:00 2001 From: pqcqaq <905739777@qq.com> Date: Fri, 19 Jul 2024 12:24:01 +0800 Subject: [PATCH] color update al --- src/stores/theme/index.ts | 26 ++++--- src/utils/function/index.ts | 33 +++++++++ src/utils/theme/index.ts | 135 ++++++++++++++++++++++++++++-------- typings/index.ts | 16 ++++- 4 files changed, 172 insertions(+), 38 deletions(-) diff --git a/src/stores/theme/index.ts b/src/stores/theme/index.ts index 9a72159..7a26dd4 100644 --- a/src/stores/theme/index.ts +++ b/src/stores/theme/index.ts @@ -1,6 +1,7 @@ import { ColorSchema } from "../../../typings"; import { proxyWithHistory } from "valtio-history"; -import { createDarkTheme, createLightTheme } from "../../utils/theme"; +import { changeThemeSchema } from "../../utils/theme"; +import { subscribe } from "valtio"; // // 模拟计算属性 // watch((get) => { @@ -8,23 +9,28 @@ import { createDarkTheme, createLightTheme } from "../../utils/theme"; // counterStore.double = counterStore.count * 2 // }) -const initString = `{"onLight": {}, "onDark": {}}`; +const initValue = { + onLight: {}, + onDark: {}, +}; export const useThemeStore = proxyWithHistory({ // 取值的时候,本地存储有就从本地获取 colors: JSON.parse( - localStorage.getItem("colors") || initString + localStorage.getItem("colors") || JSON.stringify(initValue) ) as ColorSchema, init: () => { - createLightTheme(useThemeStore.value.colors.onLight); - createDarkTheme(useThemeStore.value.colors.onDark!); + changeThemeSchema(useThemeStore.value.colors); }, updateColors: (value: ColorSchema) => { - // 更新的时候,订阅更新一下本地存储 - localStorage.setItem("colors", JSON.stringify(value)); - // 在更新的时候同步更新到style - createLightTheme(value.onLight); - createDarkTheme(value.onDark!); useThemeStore.value.colors = value; }, }); + +subscribe(useThemeStore, () => { + // 更新的时候,订阅更新一下本地存储 + localStorage.setItem("colors", JSON.stringify(useThemeStore.value.colors)); + // 在更新的时候同步更新到style + changeThemeSchema(useThemeStore.value.colors); + console.log("useThemeStore updated"); +}); diff --git a/src/utils/function/index.ts b/src/utils/function/index.ts index 06466a1..d461f8c 100644 --- a/src/utils/function/index.ts +++ b/src/utils/function/index.ts @@ -1,3 +1,5 @@ +import { Change } from "../../../typings"; + export const useDebounce = (fn: Function, delay: number) => { let timeout: any; return (...args: any[]) => { @@ -5,3 +7,34 @@ export const useDebounce = (fn: Function, delay: number) => { timeout = setTimeout(() => fn(...args), delay); }; }; + +/** + * 获取对象比较的结果 + * @param obj1 原始对象 + * @param obj2 目标对象 + * @returns 返回修改的key + */ +export function compareObjects( + obj1: Record, + obj2: Record +): Change[] { + const changes: Change[] = []; + + for (const key in obj1) { + if (obj1.hasOwnProperty(key)) { + if (!obj2.hasOwnProperty(key)) { + changes.push({ key, type: "remove" }); + } else if (obj1[key] !== obj2[key]) { + changes.push({ key, type: "update" }); + } + } + } + + for (const key in obj2) { + if (obj2.hasOwnProperty(key) && !obj1.hasOwnProperty(key)) { + changes.push({ key, type: "add" }); + } + } + + return changes; +} diff --git a/src/utils/theme/index.ts b/src/utils/theme/index.ts index f6658f3..d437c1e 100644 --- a/src/utils/theme/index.ts +++ b/src/utils/theme/index.ts @@ -3,12 +3,14 @@ import { ReverseHandlerConfig, RGBString, RGBValue, + ThemeBlockCache, + ThemeMode, ThemeSection, ThemeVariables, UpdateThemeColor, } from "../../../typings"; import { themeColorSchema } from "../../data/colors"; -import { useDebounce } from "../function"; +import { compareObjects, useDebounce } from "../function"; /** * 更新主题颜色 @@ -30,6 +32,20 @@ export function updateThemeColor({ } } +export function generateCssText( + themeClass: string, + themeVariables: ThemeVariables +): string { + let cssRules = `.${themeClass} {`; + for (const variable in themeVariables) { + if (themeVariables.hasOwnProperty(variable)) { + cssRules += `--${variable}: ${themeVariables[variable]};`; + } + } + cssRules += "}"; + return cssRules; +} + /** * 创建主题 * @param themeClass 主题类名 @@ -48,14 +64,8 @@ export function createTheme( //设置id属性,方便后面进行删除等操作 styleSheet.id = id; - // 构建 CSS 规则 - let cssRules = `.${themeClass} {`; - for (const variable in themeVariables) { - if (themeVariables.hasOwnProperty(variable)) { - cssRules += `--${variable}: ${themeVariables[variable]};`; - } - } - cssRules += "}"; + // // 构建 CSS 规则 + const cssRules = generateCssText(themeClass, themeVariables); // 插入 CSS 规则到样式表中 if ((styleSheet as any).styleSheet) { @@ -68,6 +78,14 @@ export function createTheme( // 将样式表添加到文档头部 document.head.appendChild(styleSheet); + if (themeClass === themeMap.light) { + themeLightCache.obj = themeVariables; + } + + if (themeClass === themeMap.dark) { + themeDarkCache.obj = themeVariables; + } + return id; } @@ -371,10 +389,10 @@ const themeMap = { */ export const createLightTheme = (themeVariables: ThemeVariables) => { return useDebounce(() => { - if (themeLightId) { - document.getElementById(themeLightId)?.remove(); + if (themeLightCache.id) { + document.getElementById(themeLightCache.id)?.remove(); } - themeLightId = createTheme(themeMap.light, themeVariables); + themeLightCache.id = createTheme(themeMap.light, themeVariables); }, 50)(); }; @@ -385,10 +403,10 @@ export const createLightTheme = (themeVariables: ThemeVariables) => { */ export const createDarkTheme = (themeVariables: ThemeVariables) => { return useDebounce(() => { - if (themeDarkId) { - document.getElementById(themeDarkId)?.remove(); + if (themeDarkCache.id) { + document.getElementById(themeDarkCache.id)?.remove(); } - themeDarkId = createTheme(themeMap.dark, themeVariables); + themeDarkCache.id = createTheme(themeMap.dark, themeVariables); }, 50)(); }; @@ -410,17 +428,23 @@ export const getColorAsync = async () => { /** * 主题ID */ -let themeLightId: string | null = null; -let themeDarkId: string | null = null; +const themeLightCache: ThemeBlockCache = { + id: "", + obj: {}, +}; +const themeDarkCache: ThemeBlockCache = { + id: "", + obj: {}, +}; // 在退出的时候删除这两个主题,防止重复加载 window.addEventListener("unload", () => { setTimeout(() => { - if (themeLightId) { - document.getElementById(themeLightId)?.remove(); + if (themeLightCache.id) { + document.getElementById(themeLightCache.id)?.remove(); } - if (themeDarkId) { - document.getElementById(themeDarkId)?.remove(); + if (themeDarkCache.id) { + document.getElementById(themeDarkCache.id)?.remove(); } }, 0); }); @@ -431,14 +455,71 @@ window.addEventListener("unload", () => { */ export const changeThemeSchema = (schema: ColorSchema) => { // 通过id删除原有的主题,然后重新生成 - if (themeLightId) { - document.getElementById(themeLightId)?.remove(); + if (themeLightCache.id) { + // document.getElementById(themeLightId)?.remove(); + updateThemeBlock("light", schema.onLight); + } else { + themeLightCache.id = createTheme(themeMap.light, schema.onLight); } - if (themeDarkId) { - document.getElementById(themeDarkId)?.remove(); + if (themeDarkCache.id) { + // document.getElementById(themeDarkId)?.remove(); + updateThemeBlock("dark", schema.onDark!); + } else { + themeDarkCache.id = createTheme(themeMap.dark, schema.onDark!); + } +}; + +/** + * 根据对象更新关系检查来更新主题块 + * @param mode 主题模式 + * @param colors 主题颜色 + * @returns 主题块 + */ +export const updateThemeBlock = (mode: ThemeMode, colors: ThemeVariables) => { + // 通过id拿到block然后更新里面的内容 + const id = mode == "light" ? themeLightCache.id : themeDarkCache.id; + + if (!id) { + throw new Error("Theme ID not found"); + return; + } + const block = document.getElementById(id); + if (block) { + const innerText = block.innerText; + let result; + if (mode == "light") { + result = compareObjects(themeLightCache.obj, colors); + } else { + result = compareObjects(themeDarkCache.obj, colors); + } + + if (!(result && result.length)) { + return; + } + + let newText = innerText; + + result.forEach((item) => { + switch (item.type) { + case "update": + const regUpdate = new RegExp(`--${item.key}:.*?;`, "g"); + newText = innerText.replace( + regUpdate, + `--${item.key}: ${colors[item.key]};` + ); + break; + case "remove": + const regRemove = new RegExp(`--${item.key}:.*?;`, "g"); + newText = innerText.replace(regRemove, ""); + break; + case "add": + newText = `${innerText}\n--${item.key}: ${colors[item.key]};`; + break; + } + }); + + block.innerText = newText; } - themeLightId = createTheme(themeMap.light, schema.onLight); - themeDarkId = createTheme(themeMap.dark, schema.onDark!); }; /** diff --git a/typings/index.ts b/typings/index.ts index 4eeeabd..c3847ef 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -43,4 +43,18 @@ export type ThemeSection = "dark" | "light" | "system"; export type ReverseHandlerType = "reverse" | "none" | "lighten" | "darken"; -export type ReverseHandlerConfig = Record; \ No newline at end of file +export type ReverseHandlerConfig = Record; + +export type ThemeMode = "dark" | "light"; + +export type ThemeBlockCache = { + id: string; + obj: Record; +}; + +export type ChangeType = "update" | "remove" | "add"; + +export type Change = { + key: string; + type: ChangeType; +};