UNPKG

fairy-webuploader

Version:

301 lines (255 loc) 11.8 kB
import AbstractTemplate from "./AbstractTemplate.js"; export default class ModernFileTemplate extends AbstractTemplate{ constructor(el, options) { super(el, options); } initStyles(styleId) { this.brandColor = '#4CAF50'; this.isDarkMode = true; const style = document.createElement('style'); style.id = styleId; style.textContent = ` /* 基础样式 */ .file-uploader-container { background: linear-gradient(135deg, #f5f5f5, #f0eaea); border-radius: 8px; border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); padding: 40px; text-align: center; width: 100%; max-width: 100%; transition: all 0.3s ease; position: relative; overflow: hidden; } /* 几何波纹装饰 */ .file-uploader-container::before { content: ''; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="rgba(0,0,0,0.03)" stroke-width="1"><path d="M200 0v400M0 200h400"/></svg>'); background-size: 50px 50px; opacity: 0.2; pointer-events: none; animation: wave 10s linear infinite; } @keyframes wave { 0% { transform: translate(-25px, -25px); } 100% { transform: translate(25px, 25px); } } /* 图标 */ .upload-icon { width: 64px; height: 64px; fill: #999; transition: transform 0.3s ease; } .file-uploader-container:hover .upload-icon { transform: scale(1.1); } /* 提示文案 */ .upload-text { font-family: 'SF Pro', 'Roboto', sans-serif; font-size: 14px; color: #999; margin-top: 16px; transition: color 0.3s ease; } /* 悬停状态 */ .file-uploader-container:hover { background-color: #fafafa; border-color: ${this.brandColor}; cursor: pointer; } .file-uploader-container:hover .upload-text { color: ${this.brandColor}; } /* 拖拽激活状态 */ .file-uploader-container.drag-active { border: 2px dashed rgba(${parseInt(this.brandColor.slice(1, 3), 16)}, ${parseInt(this.brandColor.slice(3, 5), 16)}, ${parseInt(this.brandColor.slice(5, 7), 16)}, 0.3); background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="none" stroke="rgba(0,0,0,0.05)" stroke-width="1"><path d="M0 20h40M20 0v40"/></svg>'); background-size: 20px 20px; animation: grid-move 2s linear infinite; } @keyframes grid-move { 0% { background-position: 0 0; } 100% { background-position: 20px 20px; } } /* 上传进度条 */ .progress-bar { height: 4px; background-color: #eee; border-radius: 2px; margin-top: 16px; overflow: hidden; } .progress { height: 100%; background-color: ${this.brandColor}; width: 0%; transition: width 0.3s ease; position: relative; } .progress::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); animation: shine 2s infinite; } @keyframes shine { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } /* 成功提示 */ .success-icon { width: 32px; height: 32px; fill: ${this.brandColor}; opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease; transform: scale(0.5); } .success-icon.show { opacity: 1; transform: scale(1); } /* 错误状态 */ .error-state { background-color: #ffebee; border-color: #ef5350; } .error-text { color: #ef5350; display: flex; align-items: center; justify-content: center; } .error-text::before { content: '😅'; margin-right: 8px; } /* 暗黑模式 */ .dark-mode .file-uploader-container { background-color: #3a3a3a; border-color: #555; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } .dark-mode .file-uploader-container::before { opacity: 0.1; } .dark-mode .upload-icon { fill: #bbb; } .dark-mode .upload-text { color: #bbb; } .dark-mode .file-uploader-container:hover { background-color: #444; border-color: ${this.brandColor}; } .dark-mode .file-uploader-container:hover .upload-text { color: ${this.brandColor}; } .dark-mode .file-uploader-container.drag-active { border-color: rgba(${parseInt(this.brandColor.slice(1, 3), 16)}, ${parseInt(this.brandColor.slice(3, 5), 16)}, ${parseInt(this.brandColor.slice(5, 7), 16)}, 0.3); } .dark-mode .progress-bar { background-color: #555; } .dark-mode .error-state { background-color: #4a3a3a; border-color: #ef5350; } .dark-mode .error-text { color: #ef5350; } `; document.head.appendChild(style); } createUploader() { this.uploaderContainer = document.createElement('div'); this.uploaderContainer.className = 'file-uploader-container'; this.uploaderContainer.id = AbstractTemplate.uploaderContainerId const uploadIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); uploadIcon.classList.add('upload-icon'); uploadIcon.setAttribute('viewBox', '0 0 24 24'); uploadIcon.innerHTML = ` <path d="M19 13h-6v6h-2v-6H5l7-7 7 7zM5 5v2h14V5H5z"/> `; const uploadText = document.createElement('div'); uploadText.className = 'upload-text'; uploadText.textContent = '点击或拖拽文件到此处'; const input = document.createElement('input'); input.id = AbstractTemplate.uploaderInputId; input.type = 'file'; input.style.display = 'none'; input.multiple = this.options?.multiple || true; input.accept = this.options?.accept || '*'; this.progressBar = document.createElement('div'); this.progressBar.className = 'progress-bar'; this.progress = document.createElement('div'); this.progress.className = 'progress'; this.progressBar.appendChild(this.progress); this.successIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); this.successIcon.classList.add('success-icon'); this.successIcon.setAttribute('viewBox', '0 0 24 24'); this.successIcon.innerHTML = ` <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/> `; this.uploaderContainer.appendChild(uploadIcon); this.uploaderContainer.appendChild(uploadText); this.uploaderContainer.appendChild(input); this.uploaderContainer.appendChild(this.progressBar); this.uploaderContainer.appendChild(this.successIcon); this.container.appendChild(this.uploaderContainer); this.input = input; } setupEventListeners() { this.uploaderContainer.addEventListener('click', () => { this.input.click(); }); this.input.addEventListener('change', (e) => { this.handleFileSelect(e.target.files); }); this.uploaderContainer.addEventListener('dragover', (e) => { e.preventDefault(); this.uploaderContainer.classList.add('drag-active'); }); this.uploaderContainer.addEventListener('dragleave', () => { this.uploaderContainer.classList.remove('drag-active'); }); this.uploaderContainer.addEventListener('drop', (e) => { e.preventDefault(); this.uploaderContainer.classList.remove('drag-active'); this.handleFileSelect(e.dataTransfer.files); }); // 模拟暗黑模式切换 document.addEventListener('keydown', (e) => { if (e.key === 'd') { this.toggleDarkMode(); } }); } showSuccess() { this.successIcon.classList.add('show'); // 微震动效果 this.uploaderContainer.style.animation = 'shake 0.5s'; setTimeout(() => { this.uploaderContainer.style.animation = ''; this.progress.style.width = '0%'; this.successIcon.classList.remove('show'); }, 1500); } toggleDarkMode() { this.isDarkMode = !this.isDarkMode; document.body.classList.toggle('dark-mode', this.isDarkMode); } }