const themeColor = {}; /** * 单例模式确保全局只有一个Color实例 * @param {Object} themeColor 主题颜色 */ const Color = (function () { let instance; return function (themeColor) { if (instance) return instance; return new ColorConstructor(themeColor); }; })(); class ColorConstructor { // 定义私有属性,用于存储主题颜色和颜色变化程度 #themeColor; // 主题颜色 #changeSpan; // 颜色变化程度 #themeKey; // 主题颜色key #subThemeKey; // 辅助颜色key #theme; // 主题 constructor({ themeColor, changeSpan, themeKey, theme = "light", subThemeKey, }) { // 如果没有传入主题颜色,则抛出错误 if (!themeColor) throw new Error(`主题颜色是必须的`); // 设置主题 this.setTheme(theme); // 设置主题颜色 this.setThemeColor({ themeColor, changeSpan, themeKey, theme, subThemeKey, }); } // 判断颜色是否为16进制颜色 isHEX(color) { // 如果颜色长度不为7或4,则返回false if (color.length !== 7 && color.length !== 4) return false; // 定义正则表达式,用于匹配16进制颜色 const hexreg = /^\#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/; // 返回正则表达式匹配结果 return hexreg.test(color); } isRGB(color) { const rgbreg = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/; return rgbreg.test(color); } // 格式化十六进制颜色值 formatHex(hex) { // 如果长度不等于4,则返回原值 if (hex.length !== 4) return hex; // 返回格式化后的十六进制颜色值 return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`; } // 参数归一化颜色 normalizeColor(color) { let colorMap = {}; if (typeof color === "string") { if (!this.isHEX(color) && !this.isRGB(color)) { throw new Error(`颜色值${color}格式不正确`); } colorMap[this.#themeKey] = color; } else if (Object.prototype.toString.call(color) !== "[object Object]") { throw new Error(`颜色值${color}格式不正确 必须是字符串或者对象的形式`); } else { colorMap = color; } return colorMap; } // 设置主题颜色 setThemeColor({ themeColor, changeSpan = 0.2, themeKey = "primary", subThemeKey = "success", onSuccess, }) { // 将传入的颜色赋值给私有属性#themeColor const newTheme = this.normalizeColor(themeColor); this.#changeSpan = changeSpan; this.#themeColor = this.#setThemeMap(newTheme, this.#changeSpan); this.#themeKey = themeKey; this.#subThemeKey = subThemeKey; onSuccess?.(this.#themeColor); } // 设置主题 setTheme(theme) { if (theme !== "dark" && theme !== "light") throw new Error(`主题必须是dark或者light`); // 将传入的主题赋值给私有属性#theme this.#theme = theme; // 调用私有方法#setThemeMap,传入私有属性#themeColor和#changeSpan,将返回值赋值给私有属性#themeColor this.#themeColor = this.#setThemeMap(this.#themeColor, this.#changeSpan); } // 获取主题颜色 get themeColor() { // 返回主题颜色 return this.#themeColor[this.#themeKey]; } // 获取子主题颜色 get subThemeColor() { // 返回主题颜色中子主题键对应的颜色值 return this.#themeColor[this.#subThemeKey]; } // 获取变淡以及加深的颜色 #setThemeMap(themeColor, changeSpan) { const newTheme = { ...themeColor }; const changeList = new Array(5) .fill(0) .map((_, index) => index * changeSpan) .filter((item) => item > 0 && item < 1); for (const key in newTheme) { changeList.forEach((item, index) => { newTheme[`${key}-light-${index + 1}`] = this.getLightColor( newTheme[key], item ); newTheme[`${key}-dark-${index + 1}`] = this.getDarkColor( newTheme[key], item ); }); } return newTheme; } // 获取主题颜色 1-4 或者 空 getThemeColor(index, themeKey = this.#themeKey) { // 打印深色主题颜色 const key = `${themeKey}${!!index ? `-${this.#theme}-${index}` : ""}`; return this.#themeColor[key]; } //16进制颜色转GRB颜色 HexToRgb(str) { if (!this.isHEX(str)) { return; } str = this.formatHex(str); let hexs = null; str = str.replace("#", ""); // 去掉# hexs = str.match(/../g); // 切割成数组 409EFF => ['40','9E','FF'] // 将切割的色值转换为16进制 for (let i = 0; i < hexs.length; i++) hexs[i] = parseInt(hexs[i], 16); return hexs; } //GRB颜色转16进制颜色 rgbaToHex(rgba) { let hex = "#"; for (const i of rgba) { hex += i.toString(16).padStart(2, "0"); } return hex; } // 计算颜色 computedColor(color, fn) { // 将颜色转换为rgb格式 let rgb = color; if (this.isHEX(color)) { rgb = this.HexToRgb(color); } // 创建一个空数组,用于存储转换后的颜色值 let sColorChange = []; // 遍历rgb数组 for (var i = 0; i < rgb.length; i++) { // 对每个颜色值进行转换 let val = fn(rgb[i]); // 如果转换后的值小于0,则将其设置为0 if (val < 0) { val = 0; } // 如果转换后的值大于255,则将其设置为255 if (val > 255) { val = 255; } // 将转换后的值添加到数组中 sColorChange.push(val); } // 将转换后的rgb数组转换为hex格式 return this.rgbaToHex(sColorChange); } //得到16进制颜色值为color的加深颜色值,level为加深的程度,限0-1之间 getDarkColor(color, level) { return this.computedColor(color, (item) => item - Math.floor(item * level)); } //得到16进制颜色值为color的减淡颜色值,level为加深的程度,限0-1之间 getLightColor(color, level) { return this.computedColor(color, (item) => item + Math.floor(item * level)); } } export default new Color({ themeColor });