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

GTC2026前瞻(二)Agentic AI 与开源模型篇+(三)Physical AI 与机器人篇

GTC2026前瞻(二)Agentic AI 与开源模型篇+(三)Physical AI 与机器人篇

(二)Agentic AI 与开源模型篇 Agentic AI与开源模型:英伟达想定义的,不只是“更聪明的模型”,而是“能持续工作的数字劳动力” 如果说过去两年的大模型竞赛,核心问题还是“谁能生成更像人的答案”,那么到了 GTC 2026,问题已经明显变了。英伟达把 Agentic AI 直接列为大会四大核心主题之一,官方对这一主题的定义也很明确:重点不再是单轮问答,而是让 AI agent 能够推理、规划、检索并执行动作,最终把企业数据转化为可投入生产的“数字劳动力”。这说明,Agentic AI 在英伟达的语境里,已经不是一个前沿概念,而是下一阶段 AI 商业化的主战场。(NVIDIA) 一、GTC 2026真正的变化,是 AI 开始从“会回答”走向“会做事”

医疗咨询机器人怕出事?Qwen3Guard-Gen-WEB帮你拦截风险

医疗咨询机器人怕出事?Qwen3Guard-Gen-WEB帮你拦截风险 在AI医疗应用加速落地的今天,一个现实困境正困扰着每家尝试部署智能问诊系统的机构:既要让患者获得即时、专业的健康建议,又必须确保每一句回复都经得起医学伦理、法律法规和临床安全的三重检验。一句看似无害的“试试偏方”可能延误治疗,一段模糊的“可能有风险”可能引发恐慌,而一次对禁忌症的疏漏判断,甚至可能危及生命。 更棘手的是,通用大模型并非为医疗场景而生——它不了解药品相互作用,不掌握最新诊疗指南,也无法识别患者描述中隐含的急症信号(如“头痛伴喷射性呕吐”实为颅内压增高征兆)。当医疗咨询机器人直接暴露在用户自由输入的语境中,它就像一位未经资质认证的“云医生”,能力越强,潜在风险越高。 正是在这种高敏感、零容错的现实压力下,Qwen3Guard-Gen-WEB 的出现不是锦上添花,而是雪中送炭。它并非用来生成诊断结论,而是作为一道嵌入式“安全闸门”,专为拦截那些游走在合规边缘、潜藏临床风险、违背医学常识的输出内容。它不替代医生,但能确保机器人永远不说出不该说的话。 1. 它不是医生,却是医疗AI的“执业资格审查员

Nodejs+vue3基于web的社区物业管理平台开题

Nodejs+vue3基于web的社区物业管理平台开题

文章目录 * 技术选型与架构设计 * 核心功能模块 * 性能与安全优化 * 扩展性设计 * --nodejs技术栈-- * 结论 * 源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 技术选型与架构设计 后端技术栈 * Node.js:基于Express或Koa框架构建RESTful API,处理业务逻辑与数据交互。 * 数据库:MySQL/PostgreSQL存储结构化数据(业主信息、缴费记录),Redis缓存高频访问数据(公告、权限验证)。 * 鉴权方案:JWT实现用户登录态管理,RBAC模型控制角色权限(业主、物业管理员、超级管理员)。 前端技术栈 * Vue 3:Composition API编写组件,Pinia管理全局状态(如用户信息、社区公告)。 * UI框架:Element Plus或Ant Design Vue提供表单、表格等基础组件,快速搭建管理后台。 * 可视化:ECharts展示物业费用收缴率、投诉处理进度等数据看板。

如何快速实现前端Word文档生成:DOCX.js完整使用手册

在现代Web开发中,前端直接生成Word文档已成为提升用户体验的关键技术。DOCX.js作为一款纯JavaScript实现的客户端DOCX生成库,让开发者无需后端支持就能创建专业的Microsoft Word文档。本文将为你全面解析这个强大工具的使用方法,从基础配置到高级功能,助你快速掌握前端文档生成的核心技能。 【免费下载链接】DOCX.jsGenerate Microsoft Word DOCX files in pure client-side JavaScript. Try in Chrome 项目地址: https://gitcode.com/gh_mirrors/do/DOCX.js 🎯 快速上手:5分钟创建你的第一个Word文档 想要立即体验DOCX.js的强大功能?只需三个简单步骤: 1. 引入核心依赖文件 - 在你的HTML页面中添加以下脚本引用: <script src="libs/base64.js">