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

Harness Engineering 是什么?一场新的 AI 范式已经开始

Harness Engineering 是什么?一场新的 AI 范式已经开始

1. AI 编程的一些问题(背景) 你是否在 Vibe Coding 中遇到过这些问题 1. 文档与代码脱节,上下文跟不上或冗余,导致理解偏差,代码质量越来越差;甚至之前明确告知的禁忌,在后续沟通中仍被遗忘。 2. 代码和架构偏离失控:明明一小时能做完的事,却要在反复纠正 Prompt 上绞尽脑汁,审查代码更是难受;特别是反复向对方阐述想法后,实现结果仍难以令人满意。 3. 垃圾代码越来越多:不会主动清理上一轮遗留的废代码,反而基于它继续构建,导致废料不断堆积。 4. 生成的代码审查起来令人头疼,不敢未经严格审查就直接上线,否则一旦出问题肯定要被背锅 整体看来,缺少的是约束、正确引导和及时修正反馈等机制。Harness Engineering 正是在这一背景下出现的。 2. Harness Engineering 出现 随着工程实践的深入,从上下文工程,逐步进化到 Harness Engineering 了。Harness

C#初级开发者:AI预测重构需求下的创意守护与效率革命——老码农的幽默实战录

C#初级开发者:AI预测重构需求下的创意守护与效率革命——老码农的幽默实战录

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎点赞 + 收藏 + 关注哦 💕 📚 本文简介 本文探讨了C#初级开发者在AI时代的挑战,特别是AI分析代码库历史记录预测重构需求导致的主动性焦虑。文章分析了AI预测的工作原理,揭示了其在C#环境中的局限性,并通过代码示例和案例展示了开发者如何保持创意和主导权。作者提供了实战策略,如提升代码质量、利用AI工具辅助,以及培养业务洞察力,帮助开发者从焦虑转向高效行动。核心观点认为,AI虽能优化流程,但人类开发者的情境理解和创新思维仍是不可替代的竞争优势。 目录 * 📚 本文简介 * 📚 引言:当AI开始“读心”代码库,初级C#开发者的焦虑与转机 * 📚 一、AI分析代码库历史记录的真相:是“预言家”还是“复读机”? * 📘1、AI如何预测重构需求:基于模式匹配的“高级猜谜” * 📘2、C#代码库的特点与AI分析:强类型语言的“双刃剑”

当开发者遇上AI副驾驶:效率翻倍还是技能退化?

当开发者遇上AI副驾驶:效率翻倍还是技能退化?

在 AI 技术飞速渗透各行各业的当下,我们早已告别 “谈 AI 色变” 的观望阶段,迈入 “用 AI 提效” 的实战时代 💡。无论是代码编写时的智能辅助 💻、数据处理中的自动化流程 📊,还是行业场景里的精准解决方案 ,AI 正以润物细无声的方式,重构着我们的工作逻辑与行业生态 🌱。今天,我想结合自身实战经验,带你深入探索 AI 技术如何打破传统工作壁垒 🧱,让 AI 真正从 “概念” 变为 “实用工具” ,为你的工作与行业发展注入新动能 ✨。 文章目录 * 当开发者遇上AI副驾驶:效率翻倍还是技能退化? 🚀 * 一、AI副驾驶的崛起:从辅助到协作 💡 * 1.1 什么是AI副驾驶? * 1.2 技术基础:大模型如何理解代码? * 二、效率翻倍:AI如何加速开发流程 ⚡ * 2.1 减少样板代码(