426 lines
15 KiB
JavaScript
426 lines
15 KiB
JavaScript
// 随机颜色/颜色转换工具 JavaScript
|
||
|
||
class ColorTool {
|
||
constructor() {
|
||
this.apiUrl = 'https://60s.api.shumengya.top/v2/color';
|
||
this.init();
|
||
}
|
||
|
||
init() {
|
||
this.bindEvents();
|
||
this.hideResultSection();
|
||
}
|
||
|
||
bindEvents() {
|
||
const randomBtn = document.getElementById('randomBtn');
|
||
const convertBtn = document.getElementById('convertBtn');
|
||
const colorInput = document.getElementById('colorInput');
|
||
|
||
randomBtn.addEventListener('click', () => this.getRandomColor());
|
||
convertBtn.addEventListener('click', () => this.convertColor());
|
||
|
||
// 回车键支持
|
||
colorInput.addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') {
|
||
this.convertColor();
|
||
}
|
||
});
|
||
}
|
||
|
||
hideResultSection() {
|
||
const resultSection = document.querySelector('.result-section');
|
||
resultSection.style.display = 'none';
|
||
}
|
||
|
||
showResultSection() {
|
||
const resultSection = document.querySelector('.result-section');
|
||
resultSection.style.display = 'block';
|
||
}
|
||
|
||
showLoading() {
|
||
const loading = document.getElementById('loading');
|
||
const error = document.getElementById('error');
|
||
loading.style.display = 'block';
|
||
error.style.display = 'none';
|
||
this.hideResultSection();
|
||
}
|
||
|
||
hideLoading() {
|
||
const loading = document.getElementById('loading');
|
||
loading.style.display = 'none';
|
||
}
|
||
|
||
showError(message) {
|
||
const error = document.getElementById('error');
|
||
const errorMessage = document.getElementById('errorMessage');
|
||
const loading = document.getElementById('loading');
|
||
|
||
loading.style.display = 'none';
|
||
errorMessage.textContent = message;
|
||
error.style.display = 'block';
|
||
this.hideResultSection();
|
||
}
|
||
|
||
hideError() {
|
||
const error = document.getElementById('error');
|
||
error.style.display = 'none';
|
||
}
|
||
|
||
async getRandomColor() {
|
||
try {
|
||
this.showLoading();
|
||
const encoding = document.getElementById('encodingSelect').value;
|
||
const url = `${this.apiUrl}?encoding=${encoding}`;
|
||
|
||
const response = await fetch(url);
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.code === 200) {
|
||
this.displayColorData(data.data);
|
||
this.hideLoading();
|
||
this.hideError();
|
||
this.showResultSection();
|
||
} else {
|
||
throw new Error(data.message || '获取颜色信息失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取随机颜色失败:', error);
|
||
this.showError(`获取随机颜色失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
async convertColor() {
|
||
const colorInput = document.getElementById('colorInput');
|
||
const colorValue = colorInput.value.trim();
|
||
|
||
if (!colorValue) {
|
||
this.showError('请输入要转换的颜色值');
|
||
return;
|
||
}
|
||
|
||
// 简单的颜色格式验证
|
||
if (!this.isValidColor(colorValue)) {
|
||
this.showError('请输入有效的颜色值(如 #33AAFF)');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
this.showLoading();
|
||
const encoding = document.getElementById('encodingSelect').value;
|
||
const url = `${this.apiUrl}?color=${encodeURIComponent(colorValue)}&encoding=${encoding}`;
|
||
|
||
const response = await fetch(url);
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.code === 200) {
|
||
this.displayColorData(data.data);
|
||
this.hideLoading();
|
||
this.hideError();
|
||
this.showResultSection();
|
||
} else {
|
||
throw new Error(data.message || '转换颜色失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('转换颜色失败:', error);
|
||
this.showError(`转换颜色失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
isValidColor(color) {
|
||
// 支持十六进制颜色格式
|
||
const hexPattern = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
|
||
// 支持RGB格式
|
||
const rgbPattern = /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/;
|
||
// 支持HSL格式
|
||
const hslPattern = /^hsl\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*\)$/;
|
||
|
||
return hexPattern.test(color) || rgbPattern.test(color) || hslPattern.test(color);
|
||
}
|
||
|
||
displayColorData(data) {
|
||
// 显示主要颜色信息
|
||
this.updateColorDisplay(data);
|
||
|
||
// 显示各种格式
|
||
this.updateColorFormats(data);
|
||
|
||
// 显示颜色属性
|
||
this.updateColorProperties(data);
|
||
|
||
// 显示配色方案
|
||
this.updateColorPalette(data);
|
||
|
||
// 显示无障碍性信息
|
||
this.updateAccessibilityInfo(data);
|
||
}
|
||
|
||
updateColorDisplay(data) {
|
||
const colorDisplay = document.getElementById('colorDisplay');
|
||
const colorName = document.getElementById('colorName');
|
||
const hexValue = document.getElementById('hexValue');
|
||
|
||
colorDisplay.style.backgroundColor = data.hex;
|
||
colorName.textContent = data.name || '未知颜色';
|
||
hexValue.textContent = data.hex;
|
||
}
|
||
|
||
updateColorFormats(data) {
|
||
// RGB
|
||
if (data.rgb) {
|
||
document.getElementById('rgbR').textContent = data.rgb.r;
|
||
document.getElementById('rgbG').textContent = data.rgb.g;
|
||
document.getElementById('rgbB').textContent = data.rgb.b;
|
||
document.getElementById('rgbString').textContent = data.rgb.string;
|
||
}
|
||
|
||
// HSL
|
||
if (data.hsl) {
|
||
document.getElementById('hslH').textContent = data.hsl.h + '°';
|
||
document.getElementById('hslS').textContent = data.hsl.s + '%';
|
||
document.getElementById('hslL').textContent = data.hsl.l + '%';
|
||
document.getElementById('hslString').textContent = data.hsl.string;
|
||
}
|
||
|
||
// HSV
|
||
if (data.hsv) {
|
||
document.getElementById('hsvH').textContent = data.hsv.h + '°';
|
||
document.getElementById('hsvS').textContent = data.hsv.s + '%';
|
||
document.getElementById('hsvV').textContent = data.hsv.v + '%';
|
||
document.getElementById('hsvString').textContent = data.hsv.string;
|
||
}
|
||
|
||
// CMYK
|
||
if (data.cmyk) {
|
||
document.getElementById('cmykC').textContent = data.cmyk.c + '%';
|
||
document.getElementById('cmykM').textContent = data.cmyk.m + '%';
|
||
document.getElementById('cmykY').textContent = data.cmyk.y + '%';
|
||
document.getElementById('cmykK').textContent = data.cmyk.k + '%';
|
||
document.getElementById('cmykString').textContent = data.cmyk.string;
|
||
}
|
||
|
||
// LAB
|
||
if (data.lab) {
|
||
document.getElementById('labL').textContent = data.lab.l;
|
||
document.getElementById('labA').textContent = data.lab.a;
|
||
document.getElementById('labB').textContent = data.lab.b;
|
||
document.getElementById('labString').textContent = data.lab.string;
|
||
}
|
||
}
|
||
|
||
updateColorProperties(data) {
|
||
// 亮度
|
||
if (data.brightness !== undefined) {
|
||
document.getElementById('brightness').textContent = data.brightness.toFixed(2);
|
||
}
|
||
|
||
// 对比度
|
||
if (data.contrast) {
|
||
document.getElementById('contrastWhite').textContent = data.contrast.white.toFixed(2);
|
||
document.getElementById('contrastBlack').textContent = data.contrast.black.toFixed(2);
|
||
}
|
||
|
||
// 最佳文字颜色
|
||
if (data.accessibility && data.accessibility.best_text_color) {
|
||
const bestTextColor = document.getElementById('bestTextColor');
|
||
bestTextColor.textContent = data.accessibility.best_text_color;
|
||
bestTextColor.style.color = data.accessibility.best_text_color;
|
||
}
|
||
}
|
||
|
||
updateColorPalette(data) {
|
||
// 互补色
|
||
if (data.complementary) {
|
||
const complementary = document.getElementById('complementary');
|
||
const complementaryHex = document.getElementById('complementaryHex');
|
||
complementary.style.backgroundColor = data.complementary;
|
||
complementaryHex.textContent = data.complementary;
|
||
}
|
||
|
||
// 类似色
|
||
if (data.analogous && data.analogous.length >= 2) {
|
||
const analogous1 = document.getElementById('analogous1');
|
||
const analogous2 = document.getElementById('analogous2');
|
||
const analogous1Hex = document.getElementById('analogous1Hex');
|
||
const analogous2Hex = document.getElementById('analogous2Hex');
|
||
|
||
analogous1.style.backgroundColor = data.analogous[0];
|
||
analogous2.style.backgroundColor = data.analogous[1];
|
||
analogous1Hex.textContent = data.analogous[0];
|
||
analogous2Hex.textContent = data.analogous[1];
|
||
}
|
||
|
||
// 三角色
|
||
if (data.triadic && data.triadic.length >= 2) {
|
||
const triadic1 = document.getElementById('triadic1');
|
||
const triadic2 = document.getElementById('triadic2');
|
||
const triadic1Hex = document.getElementById('triadic1Hex');
|
||
const triadic2Hex = document.getElementById('triadic2Hex');
|
||
|
||
triadic1.style.backgroundColor = data.triadic[0];
|
||
triadic2.style.backgroundColor = data.triadic[1];
|
||
triadic1Hex.textContent = data.triadic[0];
|
||
triadic2Hex.textContent = data.triadic[1];
|
||
}
|
||
}
|
||
|
||
updateAccessibilityInfo(data) {
|
||
if (data.accessibility) {
|
||
const aaNormal = document.getElementById('aaNormal');
|
||
const aaLarge = document.getElementById('aaLarge');
|
||
const aaaNormal = document.getElementById('aaaNormal');
|
||
const aaaLarge = document.getElementById('aaaLarge');
|
||
|
||
this.updateAccessibilityStatus(aaNormal, data.accessibility.aa_normal);
|
||
this.updateAccessibilityStatus(aaLarge, data.accessibility.aa_large);
|
||
this.updateAccessibilityStatus(aaaNormal, data.accessibility.aaa_normal);
|
||
this.updateAccessibilityStatus(aaaLarge, data.accessibility.aaa_large);
|
||
}
|
||
}
|
||
|
||
updateAccessibilityStatus(element, status) {
|
||
element.textContent = status ? '通过' : '未通过';
|
||
element.className = 'status ' + (status ? 'pass' : 'fail');
|
||
}
|
||
|
||
// 复制颜色值到剪贴板
|
||
copyToClipboard(text) {
|
||
if (navigator.clipboard) {
|
||
navigator.clipboard.writeText(text).then(() => {
|
||
this.showToast('已复制到剪贴板');
|
||
}).catch(err => {
|
||
console.error('复制失败:', err);
|
||
this.fallbackCopyTextToClipboard(text);
|
||
});
|
||
} else {
|
||
this.fallbackCopyTextToClipboard(text);
|
||
}
|
||
}
|
||
|
||
fallbackCopyTextToClipboard(text) {
|
||
const textArea = document.createElement('textarea');
|
||
textArea.value = text;
|
||
textArea.style.top = '0';
|
||
textArea.style.left = '0';
|
||
textArea.style.position = 'fixed';
|
||
|
||
document.body.appendChild(textArea);
|
||
textArea.focus();
|
||
textArea.select();
|
||
|
||
try {
|
||
const successful = document.execCommand('copy');
|
||
if (successful) {
|
||
this.showToast('已复制到剪贴板');
|
||
} else {
|
||
this.showToast('复制失败');
|
||
}
|
||
} catch (err) {
|
||
console.error('复制失败:', err);
|
||
this.showToast('复制失败');
|
||
}
|
||
|
||
document.body.removeChild(textArea);
|
||
}
|
||
|
||
showToast(message) {
|
||
// 创建简单的提示框
|
||
const toast = document.createElement('div');
|
||
toast.textContent = message;
|
||
toast.style.cssText = `
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: #2d5a27;
|
||
color: white;
|
||
padding: 12px 20px;
|
||
border-radius: 8px;
|
||
z-index: 1000;
|
||
font-size: 14px;
|
||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||
animation: slideIn 0.3s ease;
|
||
`;
|
||
|
||
// 添加动画样式
|
||
const style = document.createElement('style');
|
||
style.textContent = `
|
||
@keyframes slideIn {
|
||
from { transform: translateX(100%); opacity: 0; }
|
||
to { transform: translateX(0); opacity: 1; }
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
|
||
document.body.appendChild(toast);
|
||
|
||
setTimeout(() => {
|
||
toast.style.animation = 'slideIn 0.3s ease reverse';
|
||
setTimeout(() => {
|
||
document.body.removeChild(toast);
|
||
document.head.removeChild(style);
|
||
}, 300);
|
||
}, 2000);
|
||
}
|
||
}
|
||
|
||
// 添加点击复制功能
|
||
function addCopyListeners() {
|
||
const colorTool = window.colorTool;
|
||
|
||
// 为所有颜色值添加点击复制功能
|
||
document.addEventListener('click', (e) => {
|
||
const target = e.target;
|
||
|
||
// 检查是否点击了颜色值相关元素
|
||
if (target.id === 'hexValue' ||
|
||
target.id === 'rgbString' ||
|
||
target.id === 'hslString' ||
|
||
target.id === 'hsvString' ||
|
||
target.id === 'cmykString' ||
|
||
target.id === 'labString' ||
|
||
target.id === 'complementaryHex' ||
|
||
target.id === 'analogous1Hex' ||
|
||
target.id === 'analogous2Hex' ||
|
||
target.id === 'triadic1Hex' ||
|
||
target.id === 'triadic2Hex') {
|
||
|
||
const text = target.textContent;
|
||
if (text && colorTool) {
|
||
colorTool.copyToClipboard(text);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// 页面加载完成后初始化
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
window.colorTool = new ColorTool();
|
||
addCopyListeners();
|
||
|
||
// 添加复制提示
|
||
const style = document.createElement('style');
|
||
style.textContent = `
|
||
#hexValue, #rgbString, #hslString, #hsvString, #cmykString, #labString,
|
||
#complementaryHex, #analogous1Hex, #analogous2Hex, #triadic1Hex, #triadic2Hex {
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
#hexValue:hover, #rgbString:hover, #hslString:hover, #hsvString:hover,
|
||
#cmykString:hover, #labString:hover, #complementaryHex:hover,
|
||
#analogous1Hex:hover, #analogous2Hex:hover, #triadic1Hex:hover, #triadic2Hex:hover {
|
||
background: rgba(45, 90, 39, 0.1);
|
||
border-radius: 4px;
|
||
padding: 2px 4px;
|
||
margin: -2px -4px;
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
}); |