前端文件上传方案:别再只用input type=file了

前端文件上传方案:别再只用input type=file了

前端文件上传方案:别再只用input type=file了

毒舌时刻

这代码写得跟网红滤镜似的——仅供参考。

各位前端同行,咱们今天聊聊前端文件上传。别告诉我你还在用原生的input上传大文件,那感觉就像在用小水管灌满游泳池——慢得让人绝望。

为什么你需要文件上传方案

最近看到一个项目,上传100MB的文件直接卡死浏览器,没有任何进度提示,我差点当场去世。我就想问:你是在做上传还是在做浏览器杀手?

反面教材

<!-- 反面教材:原生文件上传 --> <input type="file" onchange="uploadFile(this.files[0])" /> <script> function uploadFile(file) { const formData = new FormData(); formData.append('file', file); // 直接上传,没有进度,没有断点续传 fetch('/api/upload', { method: 'POST', body: formData }); } </script> 

毒舌点评:这代码,我看了都替你的用户着急。原生上传大文件,你是想让用户等到天荒地老吗?

前端文件上传的正确姿势

1. 分片上传

// 正确姿势:分片上传 class ChunkUploader { constructor(file, options = {}) { this.file = file; this.chunkSize = options.chunkSize || 1024 * 1024; // 1MB this.chunks = Math.ceil(file.size / this.chunkSize); this.uploadedChunks = 0; } async upload() { const promises = []; for (let i = 0; i < this.chunks; i++) { const start = i * this.chunkSize; const end = Math.min(start + this.chunkSize, this.file.size); const chunk = this.file.slice(start, end); promises.push(this.uploadChunk(chunk, i)); } await Promise.all(promises); await this.mergeChunks(); } async uploadChunk(chunk, index) { const formData = new FormData(); formData.append('chunk', chunk); formData.append('index', index); formData.append('total', this.chunks); formData.append('filename', this.file.name); await fetch('/api/upload/chunk', { method: 'POST', body: formData }); this.uploadedChunks++; this.onProgress(this.uploadedChunks / this.chunks); } onProgress(progress) { console.log(`上传进度: ${(progress * 100).toFixed(2)}%`); } async mergeChunks() { await fetch('/api/upload/merge', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filename: this.file.name, chunks: this.chunks }) }); } } // 使用 const uploader = new ChunkUploader(file, { chunkSize: 1024 * 1024 }); uploader.upload(); 

2. 断点续传

// 正确姿势:断点续传 class ResumableUploader { constructor(file) { this.file = file; this.chunkSize = 1024 * 1024; this.uploadedChunks = new Set(); } async init() { // 获取已上传的分片 const response = await fetch(`/api/upload/status?filename=${this.file.name}`); const { uploadedChunks } = await response.json(); this.uploadedChunks = new Set(uploadedChunks); } async upload() { const chunks = Math.ceil(this.file.size / this.chunkSize); for (let i = 0; i < chunks; i++) { if (this.uploadedChunks.has(i)) { console.log(`分片${i}已上传,跳过`); continue; } const start = i * this.chunkSize; const end = Math.min(start + this.chunkSize, this.file.size); const chunk = this.file.slice(start, end); await this.uploadChunk(chunk, i); this.uploadedChunks.add(i); // 保存进度到本地 localStorage.setItem('uploadProgress', JSON.stringify([...this.uploadedChunks])); } await this.mergeChunks(); localStorage.removeItem('uploadProgress'); } async uploadChunk(chunk, index) { // 上传逻辑... } } 

3. 拖拽上传

// 正确姿势:拖拽上传 import { useCallback } from 'react'; function DragUpload({ onUpload }) { const handleDrop = useCallback((e) => { e.preventDefault(); const files = Array.from(e.dataTransfer.files); files.forEach(file => onUpload(file)); }, [onUpload]); const handleDragOver = useCallback((e) => { e.preventDefault(); }, []); return ( <div className="drag-upload" onDrop={handleDrop} onDragOver={handleDragOver} > <p>拖拽文件到此处上传</p> <input type="file" multiple onChange={(e) => { Array.from(e.target.files).forEach(file => onUpload(file)); }} /> </div> ); } 

毒舌点评:早这么写,你的上传早就做好了。别告诉我你还在用原生input,那你还是趁早去用FTP吧。

实战技巧:文件上传指南

1. 上传优化策略

  1. 分片上传:大文件切分上传
  2. 断点续传:支持暂停恢复
  3. 并发控制:限制同时上传数量
  4. 进度显示:实时显示上传进度

2. 最佳实践

// ✅ 显示上传进度 const xhr = new XMLHttpRequest(); xhr.upload.onprogress = (e) => { const progress = (e.loaded / e.total) * 100; console.log(`${progress}%`); }; // ✅ 图片预览 const preview = URL.createObjectURL(file); // ✅ 文件类型检查 const allowedTypes = ['image/jpeg', 'image/png']; if (!allowedTypes.includes(file.type)) { alert('不支持的文件类型'); return; } 

最后想说的

文件上传不是小事,是用户体验的关键。别再只用input type=file了——优化一下,你的上传会更专业。

文件上传就像快递,原生input像平邮,优化后的上传像顺丰。别让用户等平邮,给他们顺丰的体验。

Read more

PyTorch 2.6+Stable Diffusion联动教程:云端GPU双开省80%

PyTorch 2.6+Stable Diffusion联动教程:云端GPU双开省80% 你是不是也遇到过这种情况:作为一名数字艺术生,手头有创意、有想法,但一打开本地电脑跑Stable Diffusion生成一张图就得等半小时,显存还经常爆掉?更别提想同时用PyTorch训练个小模型了——8G显存根本不够分。我试过很多方法,最终发现在云端用GPU资源双开PyTorch和Stable Diffusion,不仅流畅运行,还能省下至少80%的成本。 这篇文章就是为你量身打造的实战指南。我会带你一步步在ZEEKLOG星图平台部署预装PyTorch 2.6和Stable Diffusion的镜像环境,实现两个AI工具并行运行,彻底告别卡顿与等待。整个过程不需要你懂复杂的命令行操作,所有步骤我都整理成了可复制粘贴的代码块,小白也能轻松上手。 学完这篇教程后,你能做到: - 在云端一键部署支持PyTorch 2.6 + Stable Diffusion的完整环境 - 同时运行图像生成和模型训练任务,互不干扰 - 掌握关键参数设置,提升出图质量和训练效率 - 理解为什么云端方案比本地更省钱、更

2026届毕业生存命指南:6大权威查AIGC检测入口+降AI率神器实测“红黑榜”

2026届毕业生存命指南:6大权威查AIGC检测入口+降AI率神器实测“红黑榜”

2026年的毕业季比往年都要“硬核”。 随着《学位法》正式施行,“人工智能写作”已被明确列为学术不端。 现在的毕业流程,不仅要看查重率,还要强行附带AIGC检测报告。如果AI率过高,轻则退回重改,重则影响学位。 为了帮大家少走弯路,我整理了目前国内高校认可度最高的6大检测入口,以及查出高标后的降AI神器实测榜单,帮助大家快速降低论文ai率。建议点赞收藏! 一、 权威自测:6大主流AIGC检测平台入口 不同学校、不同学科适配的工具不同,请根据你的进度“对号入座”: 1、维普 AIGC 检测(中文自查首选) * 特点: 擅长理工科逻辑分析,能识别公式推导和实验描述中的“AI感”。 * 入口: https://www.gxcqvip.com/gx-weipu/ 适用: 本科、硕士论文初稿及中稿自查。 2、万方 AIGC 检测(专业术语识别强) * 特点: 独有“

Whisper.cpp 语音识别终极指南:5分钟快速部署跨平台ASR方案

Whisper.cpp 语音识别终极指南:5分钟快速部署跨平台ASR方案 【免费下载链接】whisper.cppOpenAI 的 Whisper 模型在 C/C++ 中的移植版本。 项目地址: https://gitcode.com/GitHub_Trending/wh/whisper.cpp 想要在本地快速实现高质量语音识别?Whisper.cpp 作为 OpenAI Whisper 模型的 C++ 移植版本,为你提供了轻量级ASR解决方案。无需复杂配置,只需简单几步,就能将强大的语音识别能力集成到你的应用中!🚀 🎯 为什么选择 Whisper.cpp? 真正开箱即用的语音识别体验:告别繁琐的云端API调用,在本地即可享受与OpenAI Whisper相同的识别精度。无论是会议记录、语音助手还是音频内容分析,Whisper.cpp 都能提供稳定可靠的识别服务。 核心优势亮点: * ✅ 零外部依赖 -

颠覆级里程碑:Whisper Large-V3-Turbo重构语音交互技术范式

颠覆级里程碑:Whisper Large-V3-Turbo重构语音交互技术范式 【免费下载链接】whisper-large-v3-turbo 项目地址: https://ai.gitcode.com/hf_mirrors/openai/whisper-large-v3-turbo 技术背景:实时交互时代的语音识别困境 在智能座舱、远程医疗、元宇宙社交等新兴场景推动下,语音交互正从"可用"向"自然"跨越。行业数据显示,当语音识别延迟超过180ms时,用户对话流畅度将下降47%,而多语言混合场景的识别错误率普遍高达23%。传统语音模型面临三重矛盾:高性能模型推理成本过高(单句识别需GPU支持)、轻量化方案精度损失显著(WER提升11-15%)、多语言支持与识别速度难以兼得。OpenAI此次推出的Whisper Large-V3-Turbo,通过解码层重构+注意力机制优化的组合策略,正在改写语音识别技术的效率边界。 核心特性:解码革命与性能跃迁 架构突破:从32层到4层的极限压缩 Whisper Large-V3-Turbo实现了87.5%