yangyin
2024-12-11 4c173b743e256132e27096d38f8c9d436c13ee45
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { ElMessage } from 'element-plus';
import { genMixColor } from './gen-color'
/**
 * 颜色转换函数
 * @method hexToRgb hex 颜色转 rgb 颜色
 * @method rgbToHex rgb 颜色转 Hex 颜色
 * @method getDarkColor 加深颜色值
 * @method getLightColor 变浅颜色值
 */
export function useChangeColor() {
    // str 颜色值字符串
    const hexToRgb = (str: string): any => {
        let hexs: any = '';
        let reg = /^\#?[0-9A-Fa-f]{6}$/;
        if (!reg.test(str)) {
            ElMessage.warning('输入错误的hex');
            return '';
        }
        str = str.replace('#', '');
        hexs = str.match(/../g);
        for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16);
        return hexs;
    };
    // r 代表红色 | g 代表绿色 | b 代表蓝色
    const rgbToHex = (r: any, g: any, b: any): string => {
        let reg = /^\d{1,3}$/;
        if (!reg.test(r) || !reg.test(g) || !reg.test(b)) {
            ElMessage.warning('输入错误的rgb颜色值');
            return '';
        }
        let hexs = [r.toString(16), g.toString(16), b.toString(16)];
        for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`;
        return `#${hexs.join('')}`;
    };
    // color 颜色值字符串 | level 变浅的程度,限0-1之间
    const getDarkColor = (color: string, level: number): string => {
        let reg = /^\#?[0-9A-Fa-f]{6}$/;
        if (!reg.test(color)) {
            ElMessage.warning('输入错误的hex颜色值');
            return '';
        }
        let rgb = useChangeColor().hexToRgb(color);
        for (let i = 0; i < 3; i++) rgb[i] = Math.floor(rgb[i] * (1 - level));
        return useChangeColor().rgbToHex(rgb[0], rgb[1], rgb[2]);
    };
    // color 颜色值字符串 | level 加深的程度,限0-1之间
    const getLightColor = (color: string, level: number): string => {
        let reg = /^\#?[0-9A-Fa-f]{6}$/;
        if (!reg.test(color)) {
            ElMessage.warning('输入错误的hex颜色值');
            return '';
        }
        let rgb = useChangeColor().hexToRgb(color);
        for (let i = 0; i < 3; i++) rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]);
        return useChangeColor().rgbToHex(rgb[0], rgb[1], rgb[2]);
    };
    return {
        hexToRgb,
        rgbToHex,
        getDarkColor,
        getLightColor,
    };
}
// 主题配置类型定义
export type Theme = {
    // 这里留出可拓展空间(如banner图,背景图,文案,标题等),将主题色嵌套在对象内
    colors: {
        primary?: string;
        info?: string;
        warning?: string;
        success?: string;
        danger?: string;
    };
};
 
// 默认主题配置
export const defaultThemeConfig: Theme = {
    colors: {
        primary: '#FF6A00',
        info: '#eeeeee',
        warning: '#fbbd23',
        danger: '#f87272',
        success: '#36d399',
    },
};
 
// 本地缓存 key
const THEME_KEY = 'theme';
 
// 获取本地缓存主题
export const getTheme = (): Theme => {
    const theme = localStorage.getItem(THEME_KEY);
    return theme ? JSON.parse(theme) : defaultThemeConfig;
};
 
// 设置主题
export const setTheme = (data = defaultThemeConfig) => {
    const oldTheme = getTheme();
 
    // 将传入配置与旧的主题合并,以填补缺省的值
    data = Object.assign({}, oldTheme, data);
 
    // 将缓存到浏览器
    localStorage.setItem(THEME_KEY, JSON.stringify(data));
 
    // TODO:将主题更新到css变量中,使之生效
    updateThemeColorVar(data);
};
 
 
// ...
 
// 设置css变量
function setStyleProperty(propName: string, value: string) {
    document.documentElement.style.setProperty(propName, value);
}
 
// 更新主题色到css变量
function updateThemeColorVar({ colors }: Theme) {
    // 遍历当前主题色,生成混合色,并更新到css变量(tailwind + elementPlus)
    for (const brand in colors) {
        updateBrandExtendColorsVar(
            colors[brand as keyof Theme['colors']] as string,
            brand
        );
    }
 
    function updateBrandExtendColorsVar(color: string, name: string) {
        // TODO:生成混合色
        const { DEFAULT, dark, light } = genMixColor(color);
        // 每种主题色由浅到深分为五个阶梯以供开发者使用。
        setStyleProperty(`--${name}-lighter-color`, light[5]);
        setStyleProperty(`--${name}-light-color`, light[3]);
        setStyleProperty(`--${name}-color`, DEFAULT);
        setStyleProperty(`--${name}-deep-color`, dark[2]);
        setStyleProperty(`--${name}-deeper-color`, dark[4]);
 
        // elementPlus主题色更新
        setStyleProperty(`--el-color-${name}`, DEFAULT);
        setStyleProperty(`--el-color-${name}-dark-2`, dark[2]);
        setStyleProperty(`--el-color-${name}-light-3`, light[3]);
        setStyleProperty(`--el-color-${name}-light-5`, light[5]);
        setStyleProperty(`--el-color-${name}-light-7`, light[7]);
        setStyleProperty(`--el-color-${name}-light-8`, light[8]);
        setStyleProperty(`--el-color-${name}-light-9`, light[9]);
    }
}