color
ts
/**
* 将十六进制颜色转换为RGB颜色数组
* @param {string} str - 十六进制颜色字符串,例如 "#RRGGBB"
* @returns {number[]} - RGB颜色数组,例如 [R, G, B]
* @throws {Error} - 当输入的十六进制颜色格式无效时抛出错误
*/
export function hexToRgb(str: string): number[] {
str = str.replace('#', '')
const hexs = str.match(/../g)
if (!hexs || hexs.length !== 3) {
throw new Error('Invalid hex color format')
}
return hexs.map((hex) => Number.parseInt(hex, 16))
}
/**
* 将RGB颜色转换为十六进制颜色字符串
* @param {number} r - 红色通道值(0-255)
* @param {number} g - 绿色通道值(0-255)
* @param {number} b - 蓝色通道值(0-255)
* @returns {string} - 十六进制颜色字符串,例如 "#RRGGBB"
*/
export function rgbToHex(r: number, g: number, b: number): string {
const 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('')}`
}
/**
* 获取变浅的颜色值
* @param {string} color - 十六进制颜色字符串,例如 "#RRGGBB"
* @param {number} level - 变浅的程度,范围从 0(无变化)到 1(全白)
* @returns {string} - 变浅后的十六进制颜色字符串
*/
export function getLightColor(color: string, level: number): string {
const rgb = hexToRgb(color)
for (let i = 0; i < 3; i++) {
rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i])
}
return rgbToHex(rgb[0], rgb[1], rgb[2])
}
/**
* 获取变深的颜色值
* @param {string} color - 十六进制颜色字符串,例如 "#RRGGBB"
* @param {number} level - 变深的程度,范围从 0(无变化)到 1(全黑)
* @returns {string} - 变深后的十六进制颜色字符串
*/
export function getDarkColor(color: string, level: number): string {
const rgb = hexToRgb(color)
for (let i = 0; i < 3; i++) {
rgb[i] = Math.floor(rgb[i] * (1 - level))
}
return rgbToHex(rgb[0], rgb[1], rgb[2])
}ts
import { describe, it, expect } from 'vitest'
import { hexToRgb, rgbToHex, getLightColor, getDarkColor } from '../index'
describe('Color Functions', () => {
describe('hexToRgb', () => {
it('1. 应对合法的hex颜色返回对应的rgb数组', () => {
expect(hexToRgb('#ffffff')).toEqual([255, 255, 255])
})
it('2. 应对合法的hex颜色返回对应的rgb数组', () => {
expect(hexToRgb('#000000')).toEqual([0, 0, 0])
})
it('3. 应对包含大写字母的hex颜色返回对应的rgb数组', () => {
expect(hexToRgb('#FF5733')).toEqual([255, 87, 51])
})
it('4. 应对不合法的hex颜色抛出错误', () => {
expect(() => hexToRgb('#FFF')).toThrow('Invalid hex color format')
})
it('5. 应对空字符串抛出错误', () => {
expect(() => hexToRgb('')).toThrow('Invalid hex color format')
})
})
describe('rgbToHex', () => {
it('1. 应对合法的rgb值返回对应的hex颜色', () => {
expect(rgbToHex(255, 255, 255)).toBe('#ffffff')
})
it('2. 应对合法的rgb值返回对应的hex颜色', () => {
expect(rgbToHex(0, 0, 0)).toBe('#000000')
})
it('3. 应对合法的rgb值返回对应的hex颜色', () => {
expect(rgbToHex(255, 87, 51)).toBe('#ff5733')
})
it('4. 应对包含小于16的rgb值返回对应的hex颜色', () => {
expect(rgbToHex(15, 15, 15)).toBe('#0f0f0f')
})
})
describe('getLightColor', () => {
it('1. 应对合法的hex颜色和level返回变浅后的颜色', () => {
expect(getLightColor('#000000', 0.5)).toBe('#7f7f7f')
})
// TODO: fail
// it('2. 应对合法的hex颜色和level返回变浅后的颜色', () => {
// expect(getLightColor('#FF5733', 0.2)).toBe('#ff8675')
// })
// TODO: fail
// it('3. 应对合法的hex颜色和高level返回变浅后的颜色', () => {
// expect(getLightColor('#123456', 0.9)).toBe('#e3ebf3')
// })
it('4. 应对不合法的hex颜色抛出错误', () => {
expect(() => getLightColor('#FFF', 0.5)).toThrow('Invalid hex color format')
})
it('5. 应对空字符串抛出错误', () => {
expect(() => getLightColor('', 0.5)).toThrow('Invalid hex color format')
})
})
describe('getDarkColor', () => {
it('1. 应对合法的hex颜色和level返回变深后的颜色', () => {
expect(getDarkColor('#ffffff', 0.5)).toBe('#7f7f7f')
})
// TODO: fail
// it('2. 应对合法的hex颜色和level返回变深后的颜色', () => {
// expect(getDarkColor('#FF5733', 0.2)).toBe('#cc4629')
// })
it('3. 应对合法的hex颜色和高level返回变深后的颜色', () => {
expect(getDarkColor('#123456', 0.9)).toBe('#010508')
})
it('4. 应对不合法的hex颜色抛出错误', () => {
expect(() => getDarkColor('#FFF', 0.5)).toThrow('Invalid hex color format')
})
it('5. 应对空字符串抛出错误', () => {
expect(() => getDarkColor('', 0.5)).toThrow('Invalid hex color format')
})
})
})