前端文件上传方案:别再只用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

AI绘画新手必看:Face Fusion融合技巧,5分钟快速入门

AI绘画新手必看:Face Fusion融合技巧,5分钟快速入门 你是不是也和我一样,是个热爱插画创作的美术人?最近AI绘画火得一塌糊涂,朋友圈里大家都在晒“AI+手绘”作品,风格独特、效率翻倍。你也想试试,朋友还特别推荐了一个叫 Face Fusion 的工具,说它能做超自然的人脸风格迁移——比如把你画的角色脸,换成梵高笔触、赛博朋克风,甚至皮克斯动画感! 可当你兴冲冲下载软件,发现自己的Mac Mini根本跑不动——没独立显卡,CUDA不支持,安装教程全是命令行,论坛里一堆人在抱怨“配置失败”“显存不足”“Python报错”。那一刻,你是不是开始怀疑:这玩意儿真的适合我们普通人吗?难道AI辅助创作,只有程序员和高端PC玩家才能玩? 别急,今天我就来告诉你一个零门槛上手Face Fusion的方法,不用买新电脑、不用装Docker、不用懂代码,5分钟就能启动Web界面,直接上传图片做融合。关键是你用的还是真正的GPU加速环境,效果流畅、生成快、质量高。

2026 AI大模型实战:零基础玩转当下最火的AIGC

哈喽宝子们,2026年的AI大模型赛道简直卷出了新高度,中关村论坛上昆仑万维发布的Matrix-Game 3.0、SkyReels V4、Mureka V9三大世界级模型直接把全模态AIGC推上了新风口,而且昆仑天工旗下的SkyText、SkyCode等多款模型还开放了开源API,普通人也能轻松玩转AI大模型开发了。 一、当下 AI 大模型核心热点:人人都能做 AI 开发 1.全模态成主流:昆仑万维的 SkyReels V4 视频大模型实现音画一体生成、Mureka V9 音乐大模型支持创作意图精准落地,AI 从单一文本生成进入文本 / 图像 / 音频 / 视频全模态创作时代; 2.开源 API 全面开放:昆仑天工的 SkyText(文本生成)、SkyCode(代码生成)等模型开源,无需自建大模型,通过简单 API 就能实现商用级 AI 功能; 3.

5步搞定!让AI绘画直接在Photoshop中完成

还在为AI绘画的繁琐流程头疼吗?今天我要分享一个超实用的方法,让你直接在熟悉的Photoshop界面中使用AI绘画功能!ComfyUI Photoshop插件将彻底改变你的创作方式,让AI绘画变得前所未有的简单高效。 【免费下载链接】Comfy-Photoshop-SDDownload this extension via the ComfyUI manager to establish a connection between ComfyUI and the Auto-Photoshop-SD plugin in Photoshop. https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin 项目地址: https://gitcode.com/gh_mirrors/co/Comfy-Photoshop-SD 想象一下,不需要在多个软件间来回切换,不需要反复导入导出文件,一切AI创作都在你最爱的Photoshop中完成。这不仅是效率的提升,更是创作体验的全面升级! 🎯 为什么你需要这个插件

【基于无人机搭载相机网络的交互式监控分布式方法】基于无人机搭载摄像头网络的交互式监控分布式方法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 🍎 往期回顾关注个人主页:Matlab科研工作室  👇 关注我领取海量matlab电子书和数学建模资料  🍊个人信条:格物致知,完整Matlab代码获取及仿真咨询内容私信。 🔥 内容介绍 在当今社会,监控已广泛应用于安防、交通、工业生产等多个领域,对于保障社会安全、提高生产效率和优化资源管理起着至关重要的作用。传统的监控方式,如固定摄像头监控,存在监控范围有限、灵活性差等问题,难以满足复杂多变的监控需求。 基于无人机搭载摄像头网络的交互式监控分布式方法为解决这些问题提供了新的思路。无人机具有机动性强、可快速部署的特点,搭载摄像头后能够实现对大面积区域的动态监控。同时,通过构建分布式系统,将数据处理和管理分散化,提高系统的可扩展性和容错性,并实现用户与监控系统的实时交互,大大增强了监控的灵活性和针对性。这种方法在智能安防、应急救援、城市管理等众多领域具有广阔的应用前景。 相关技术与理论基础 1. 无人机技术无人机,即无人驾