Claude
重构前端架构并实现4套主题切换功能
7b4204f unverified
/**
* Magick 图像转换器 - 前端交互逻辑
* 功能:主题切换、文件上传、参数调整、表单提交
*/
(function() {
'use strict';
// ==========================================
// 1. 主题切换功能
// ==========================================
const THEME_KEY = 'magick-theme-preference';
const themeBtns = document.querySelectorAll('.theme-btn');
const body = document.body;
/**
* 应用主题到页面
* @param {string} theme - 主题名称 (apple|glass|minimal|tech)
*/
function applyTheme(theme) {
body.setAttribute('data-theme', theme);
// 更新按钮激活状态
themeBtns.forEach(btn => {
if (btn.dataset.theme === theme) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
});
// 保存到 localStorage
try {
localStorage.setItem(THEME_KEY, theme);
} catch (e) {
console.warn('无法保存主题偏好:', e);
}
}
/**
* 加载用户保存的主题偏好
*/
function loadThemePreference() {
try {
const savedTheme = localStorage.getItem(THEME_KEY);
if (savedTheme && ['apple', 'glass', 'minimal', 'tech'].includes(savedTheme)) {
return savedTheme;
}
} catch (e) {
console.warn('无法读取主题偏好:', e);
}
return 'apple'; // 默认主题
}
// 初始化主题
const initialTheme = loadThemePreference();
applyTheme(initialTheme);
// 绑定主题切换按钮事件
themeBtns.forEach(btn => {
btn.addEventListener('click', () => {
const theme = btn.dataset.theme;
applyTheme(theme);
});
});
// ==========================================
// 2. 文件上传交互
// ==========================================
const fileInput = document.getElementById('fileInput');
const selectedFile = document.getElementById('selectedFile');
const fileInputWrapper = document.querySelector('.file-input-wrapper');
/**
* 显示已选择的文件名
*/
fileInput.addEventListener('change', function() {
if (this.files.length > 0) {
const file = this.files[0];
const fileName = file.name;
const fileSize = (file.size / (1024 * 1024)).toFixed(2); // MB
selectedFile.textContent = `✓ 已选择: ${fileName} (${fileSize} MB)`;
} else {
selectedFile.textContent = '';
}
});
/**
* 拖拽上传功能
*/
fileInputWrapper.addEventListener('dragover', (e) => {
e.preventDefault();
fileInputWrapper.style.borderColor = 'var(--color-primary)';
fileInputWrapper.style.background = 'var(--bg-input-hover)';
});
fileInputWrapper.addEventListener('dragleave', (e) => {
e.preventDefault();
fileInputWrapper.style.borderColor = 'var(--border-color)';
fileInputWrapper.style.background = 'var(--bg-input)';
});
fileInputWrapper.addEventListener('drop', (e) => {
e.preventDefault();
fileInputWrapper.style.borderColor = 'var(--border-color)';
fileInputWrapper.style.background = 'var(--bg-input)';
const files = e.dataTransfer.files;
if (files.length > 0) {
fileInput.files = files;
// 触发 change 事件以显示文件名
const event = new Event('change');
fileInput.dispatchEvent(event);
}
});
// ==========================================
// 3. 质量参数滑块交互
// ==========================================
const slider = document.getElementById('setting');
const sliderValue = document.getElementById('settingValue');
const paramHint = document.getElementById('paramHint');
const modeRadios = document.querySelectorAll('input[name="mode"]');
/**
* 更新参数提示文本
*/
function updateHint() {
const mode = document.querySelector('input[name="mode"]:checked').value;
const value = parseInt(slider.value);
sliderValue.textContent = value;
if (mode === 'lossy') {
// 有损模式:质量提示
let quality = '中等';
if (value >= 90) quality = '极高';
else if (value >= 80) quality = '高';
else if (value >= 60) quality = '中等';
else if (value >= 40) quality = '中低';
else quality = '低';
paramHint.textContent = `质量: ${value} - ${quality}质量 (0=最低质量,100=最高质量)`;
} else {
// 无损模式:压缩速度提示
let speed = '平衡';
if (value <= 20) speed = '最慢/最佳压缩';
else if (value <= 40) speed = '较慢/较好压缩';
else if (value <= 60) speed = '平衡';
else if (value <= 80) speed = '较快/较差压缩';
else speed = '最快/最差压缩';
paramHint.textContent = `压缩速度: ${value} - ${speed} (0=最慢/最佳,100=最快/最差)`;
}
}
// 滑块移动时更新
slider.addEventListener('input', updateHint);
/**
* 模式切换时自动调整质量值
*/
modeRadios.forEach(radio => {
radio.addEventListener('change', function() {
const mode = document.querySelector('input[name="mode"]:checked').value;
if (mode === 'lossless') {
// 无损模式:默认最佳质量(0=最慢/最佳压缩)
slider.value = 0;
} else {
// 有损模式:默认中等质量(80=高质量)
slider.value = 80;
}
updateHint();
});
});
// 初始化提示
updateHint();
// ==========================================
// 4. 表单提交处理
// ==========================================
const form = document.getElementById('uploadForm');
const submitBtn = form.querySelector('.submit-btn');
const originalBtnText = submitBtn.textContent;
form.addEventListener('submit', function(e) {
// 显示加载状态
submitBtn.textContent = '⏳ 转换中...';
submitBtn.disabled = true;
// 如果表单提交失败,需要恢复按钮状态
// 这里使用 setTimeout 作为后备方案
setTimeout(() => {
if (submitBtn.disabled) {
submitBtn.textContent = originalBtnText;
submitBtn.disabled = false;
}
}, 60000); // 60秒超时恢复
});
// ==========================================
// 5. 键盘快捷键
// ==========================================
document.addEventListener('keydown', function(e) {
// Ctrl/Cmd + K: 聚焦文件输入
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
fileInput.click();
}
// Ctrl/Cmd + 1-4: 切换主题
if ((e.ctrlKey || e.metaKey) && e.key >= '1' && e.key <= '4') {
e.preventDefault();
const themes = ['apple', 'glass', 'minimal', 'tech'];
const themeIndex = parseInt(e.key) - 1;
applyTheme(themes[themeIndex]);
}
});
// ==========================================
// 6. 工具函数 - 参数验证
// ==========================================
/**
* 验证文件大小(客户端预检查)
*/
fileInput.addEventListener('change', function() {
if (this.files.length > 0) {
const file = this.files[0];
const maxSize = 200 * 1024 * 1024; // 200MB
if (file.size > maxSize) {
alert(`文件过大!最大支持 200MB,当前文件: ${(file.size / (1024 * 1024)).toFixed(2)} MB`);
this.value = ''; // 清空选择
selectedFile.textContent = '';
return;
}
}
});
// ==========================================
// 7. 初始化完成提示
// ==========================================
console.log('%c🧙‍♂️ Magick 图像转换器', 'font-size: 20px; font-weight: bold; color: #0071e3;');
console.log('%c✨ 前端已加载完成', 'color: #30d158;');
console.log('%c快捷键提示:', 'font-weight: bold;');
console.log(' Ctrl/Cmd + K: 打开文件选择');
console.log(' Ctrl/Cmd + 1-4: 切换主题 (1:Apple, 2:Glass, 3:Minimal, 4:Tech)');
})();