380 lines
11 KiB
JavaScript
380 lines
11 KiB
JavaScript
// API配置
|
|
const API_BASE_URL = 'https://60s.viki.moe/v2/hash';
|
|
|
|
// DOM元素
|
|
const elements = {
|
|
inputText: document.getElementById('inputText'),
|
|
processBtn: document.getElementById('processBtn'),
|
|
clearBtn: document.getElementById('clearBtn'),
|
|
resultsSection: document.getElementById('resultsSection'),
|
|
loadingOverlay: document.getElementById('loadingOverlay'),
|
|
toast: document.getElementById('toast'),
|
|
toastMessage: document.getElementById('toastMessage')
|
|
};
|
|
|
|
// 结果元素映射
|
|
const resultElements = {
|
|
md5: document.getElementById('md5Result'),
|
|
sha1: document.getElementById('sha1Result'),
|
|
sha256: document.getElementById('sha256Result'),
|
|
sha512: document.getElementById('sha512Result'),
|
|
base64Encode: document.getElementById('base64EncodeResult'),
|
|
base64Decode: document.getElementById('base64DecodeResult'),
|
|
urlEncode: document.getElementById('urlEncodeResult'),
|
|
urlDecode: document.getElementById('urlDecodeResult'),
|
|
gzipCompress: document.getElementById('gzipCompressResult'),
|
|
gzipDecompress: document.getElementById('gzipDecompressResult'),
|
|
deflateCompress: document.getElementById('deflateCompressResult'),
|
|
brotliCompress: document.getElementById('brotliCompressResult')
|
|
};
|
|
|
|
// 初始化
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initializeEventListeners();
|
|
addInputAnimation();
|
|
});
|
|
|
|
// 事件监听器初始化
|
|
function initializeEventListeners() {
|
|
// 处理按钮点击
|
|
elements.processBtn.addEventListener('click', handleProcess);
|
|
|
|
// 清空按钮点击
|
|
elements.clearBtn.addEventListener('click', handleClear);
|
|
|
|
// 输入框回车键
|
|
elements.inputText.addEventListener('keydown', function(e) {
|
|
if (e.ctrlKey && e.key === 'Enter') {
|
|
handleProcess();
|
|
}
|
|
});
|
|
|
|
// 复制按钮事件委托
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target.closest('.copy-btn')) {
|
|
const copyBtn = e.target.closest('.copy-btn');
|
|
const targetId = copyBtn.getAttribute('data-target');
|
|
const targetElement = document.getElementById(targetId);
|
|
const textContent = targetElement.textContent.trim();
|
|
|
|
if (textContent && textContent !== '等待处理...' && textContent !== '处理失败') {
|
|
copyToClipboard(textContent);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 输入框实时验证
|
|
elements.inputText.addEventListener('input', function() {
|
|
const hasContent = this.value.trim().length > 0;
|
|
elements.processBtn.disabled = !hasContent;
|
|
|
|
if (hasContent) {
|
|
elements.processBtn.classList.remove('disabled');
|
|
} else {
|
|
elements.processBtn.classList.add('disabled');
|
|
}
|
|
});
|
|
}
|
|
|
|
// 添加输入动画效果
|
|
function addInputAnimation() {
|
|
elements.inputText.addEventListener('focus', function() {
|
|
this.parentElement.classList.add('focused');
|
|
});
|
|
|
|
elements.inputText.addEventListener('blur', function() {
|
|
this.parentElement.classList.remove('focused');
|
|
});
|
|
}
|
|
|
|
// 处理主要功能
|
|
async function handleProcess() {
|
|
const inputValue = elements.inputText.value.trim();
|
|
|
|
if (!inputValue) {
|
|
showToast('请输入要处理的内容', 'error');
|
|
return;
|
|
}
|
|
|
|
// 显示加载状态
|
|
showLoading(true);
|
|
resetResults();
|
|
|
|
try {
|
|
// 调用API
|
|
const response = await fetch(`${API_BASE_URL}?content=${encodeURIComponent(inputValue)}`);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.code === 200 && data.data) {
|
|
displayResults(data.data);
|
|
showResultsSection();
|
|
showToast('处理完成!', 'success');
|
|
} else {
|
|
throw new Error(data.message || '处理失败');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('处理错误:', error);
|
|
showToast(`处理失败: ${error.message}`, 'error');
|
|
displayError();
|
|
} finally {
|
|
showLoading(false);
|
|
}
|
|
}
|
|
|
|
// 显示结果
|
|
function displayResults(data) {
|
|
try {
|
|
// 哈希结果
|
|
updateResultElement('md5', data.md5 || '不可用');
|
|
|
|
// SHA系列
|
|
if (data.sha) {
|
|
updateResultElement('sha1', data.sha.sha1 || '不可用');
|
|
updateResultElement('sha256', data.sha.sha256 || '不可用');
|
|
updateResultElement('sha512', data.sha.sha512 || '不可用');
|
|
}
|
|
|
|
// Base64编码
|
|
if (data.base64) {
|
|
updateResultElement('base64Encode', data.base64.encode || '不可用');
|
|
updateResultElement('base64Decode', data.base64.decode || '不可用');
|
|
}
|
|
|
|
// URL编码
|
|
if (data.url) {
|
|
updateResultElement('urlEncode', data.url.encode || '不可用');
|
|
updateResultElement('urlDecode', data.url.decode || '不可用');
|
|
}
|
|
|
|
// 压缩结果
|
|
if (data.gzip) {
|
|
updateResultElement('gzipCompress', data.gzip.compress || '不可用');
|
|
updateResultElement('gzipDecompress', data.gzip.decompress || '不可用');
|
|
}
|
|
|
|
if (data.deflate) {
|
|
updateResultElement('deflateCompress', data.deflate.compress || '不可用');
|
|
}
|
|
|
|
if (data.brotli) {
|
|
updateResultElement('brotliCompress', data.brotli.compress || '不可用');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('显示结果时出错:', error);
|
|
showToast('显示结果时出错', 'error');
|
|
}
|
|
}
|
|
|
|
// 更新单个结果元素
|
|
function updateResultElement(key, value) {
|
|
const element = resultElements[key];
|
|
if (element) {
|
|
const textSpan = element.querySelector('span') || element;
|
|
textSpan.textContent = value;
|
|
textSpan.classList.remove('placeholder');
|
|
|
|
// 添加动画效果
|
|
element.classList.add('slide-in');
|
|
setTimeout(() => {
|
|
element.classList.remove('slide-in');
|
|
}, 300);
|
|
}
|
|
}
|
|
|
|
// 重置结果
|
|
function resetResults() {
|
|
Object.values(resultElements).forEach(element => {
|
|
if (element) {
|
|
const textSpan = element.querySelector('span') || element;
|
|
textSpan.textContent = '等待处理...';
|
|
textSpan.classList.add('placeholder');
|
|
}
|
|
});
|
|
}
|
|
|
|
// 显示错误状态
|
|
function displayError() {
|
|
Object.values(resultElements).forEach(element => {
|
|
if (element) {
|
|
const textSpan = element.querySelector('span') || element;
|
|
textSpan.textContent = '处理失败';
|
|
textSpan.classList.add('placeholder');
|
|
}
|
|
});
|
|
}
|
|
|
|
// 显示结果区域
|
|
function showResultsSection() {
|
|
elements.resultsSection.classList.add('show');
|
|
|
|
// 平滑滚动到结果区域
|
|
setTimeout(() => {
|
|
elements.resultsSection.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start'
|
|
});
|
|
}, 100);
|
|
}
|
|
|
|
// 清空功能
|
|
function handleClear() {
|
|
elements.inputText.value = '';
|
|
elements.inputText.focus();
|
|
elements.resultsSection.classList.remove('show');
|
|
resetResults();
|
|
elements.processBtn.disabled = true;
|
|
elements.processBtn.classList.add('disabled');
|
|
|
|
showToast('内容已清空', 'info');
|
|
}
|
|
|
|
// 复制到剪贴板
|
|
async function copyToClipboard(text) {
|
|
try {
|
|
if (navigator.clipboard && window.isSecureContext) {
|
|
await navigator.clipboard.writeText(text);
|
|
} else {
|
|
// 降级方案
|
|
const textArea = document.createElement('textarea');
|
|
textArea.value = text;
|
|
textArea.style.position = 'fixed';
|
|
textArea.style.left = '-999999px';
|
|
textArea.style.top = '-999999px';
|
|
document.body.appendChild(textArea);
|
|
textArea.focus();
|
|
textArea.select();
|
|
document.execCommand('copy');
|
|
textArea.remove();
|
|
}
|
|
|
|
showToast('复制成功!', 'success');
|
|
} catch (error) {
|
|
console.error('复制失败:', error);
|
|
showToast('复制失败,请手动复制', 'error');
|
|
}
|
|
}
|
|
|
|
// 显示/隐藏加载状态
|
|
function showLoading(show) {
|
|
if (show) {
|
|
elements.loadingOverlay.classList.add('show');
|
|
elements.processBtn.disabled = true;
|
|
elements.processBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 处理中...';
|
|
} else {
|
|
elements.loadingOverlay.classList.remove('show');
|
|
elements.processBtn.disabled = false;
|
|
elements.processBtn.innerHTML = '<i class="fas fa-cogs"></i> 开始处理';
|
|
}
|
|
}
|
|
|
|
// 显示提示消息
|
|
function showToast(message, type = 'success') {
|
|
elements.toastMessage.textContent = message;
|
|
|
|
// 设置图标和样式
|
|
const icon = elements.toast.querySelector('i');
|
|
icon.className = getToastIcon(type);
|
|
|
|
elements.toast.className = `toast ${type}`;
|
|
elements.toast.classList.add('show');
|
|
|
|
// 自动隐藏
|
|
setTimeout(() => {
|
|
elements.toast.classList.remove('show');
|
|
}, 3000);
|
|
}
|
|
|
|
// 获取提示图标
|
|
function getToastIcon(type) {
|
|
const icons = {
|
|
success: 'fas fa-check-circle',
|
|
error: 'fas fa-exclamation-circle',
|
|
info: 'fas fa-info-circle',
|
|
warning: 'fas fa-exclamation-triangle'
|
|
};
|
|
return icons[type] || icons.success;
|
|
}
|
|
|
|
// 工具函数:防抖
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
// 工具函数:节流
|
|
function throttle(func, limit) {
|
|
let inThrottle;
|
|
return function() {
|
|
const args = arguments;
|
|
const context = this;
|
|
if (!inThrottle) {
|
|
func.apply(context, args);
|
|
inThrottle = true;
|
|
setTimeout(() => inThrottle = false, limit);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 添加键盘快捷键支持
|
|
document.addEventListener('keydown', function(e) {
|
|
// Ctrl+Enter 处理
|
|
if (e.ctrlKey && e.key === 'Enter') {
|
|
e.preventDefault();
|
|
if (!elements.processBtn.disabled) {
|
|
handleProcess();
|
|
}
|
|
}
|
|
|
|
// Escape 清空
|
|
if (e.key === 'Escape') {
|
|
handleClear();
|
|
}
|
|
});
|
|
|
|
// 页面可见性变化处理
|
|
document.addEventListener('visibilitychange', function() {
|
|
if (document.hidden) {
|
|
// 页面隐藏时的处理
|
|
console.log('页面已隐藏');
|
|
} else {
|
|
// 页面显示时的处理
|
|
console.log('页面已显示');
|
|
}
|
|
});
|
|
|
|
// 错误处理
|
|
window.addEventListener('error', function(e) {
|
|
console.error('全局错误:', e.error);
|
|
showToast('发生未知错误,请刷新页面重试', 'error');
|
|
});
|
|
|
|
// 未处理的Promise拒绝
|
|
window.addEventListener('unhandledrejection', function(e) {
|
|
console.error('未处理的Promise拒绝:', e.reason);
|
|
showToast('网络请求失败,请检查网络连接', 'error');
|
|
});
|
|
|
|
// 导出函数供测试使用
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = {
|
|
handleProcess,
|
|
copyToClipboard,
|
|
showToast,
|
|
debounce,
|
|
throttle
|
|
};
|
|
} |