别再手动写上传了!uni-file-picker搭配uni.uploadFile的完整实战(含多图上传与删除)

张开发
2026/6/9 23:30:15 15 分钟阅读
别再手动写上传了!uni-file-picker搭配uni.uploadFile的完整实战(含多图上传与删除)
深度解锁uni-file-picker与uni.uploadFile的进阶玩法从多图上传到全流程控制在移动应用开发中文件上传功能几乎是每个项目的标配需求。但很多开发者止步于基础实现忽略了用户体验与性能优化的细节。今天我将分享如何将uni-file-picker组件与uni.uploadFile API深度整合打造一个既美观又实用的上传模块。1. 为什么需要手动控制上传流程默认情况下uni-file-picker提供了自动上传功能看似方便却存在诸多限制无法精细控制请求时机用户选择文件后立即上传可能导致无效请求缺乏预处理能力无法在上传前对文件进行压缩或格式校验错误处理单一难以实现重试机制或替代方案进度反馈不足特别是多文件上传时体验较差通过手动控制上传流程我们可以实现// 典型的手动上传控制逻辑 handleUpload() { if (!this.selectedFiles.length) { uni.showToast({ title: 请先选择文件, icon: none }) return } this.uploadStatus uploading this.uploadFilesSequentially(0) } uploadFilesSequentially(index) { if (index this.selectedFiles.length) { this.uploadStatus completed return } const file this.selectedFiles[index] uni.uploadFile({ url: https://api.example.com/upload, filePath: file.path, name: file, formData: { customField: value }, success: () { this.uploadedCount this.uploadFilesSequentially(index 1) }, fail: (err) { this.retryUpload(index, 3) // 自动重试3次 } }) }2. 构建完整的文件选择与上传模块2.1 初始化配置与UI定制首先我们需要合理配置uni-file-picker的基础属性uni-file-picker reffilePicker v-modelfileList :auto-uploadfalse file-mediatypeimage modegrid :limit9 :image-styles{ width: 160rpx, height: 160rpx, border: { color: #eee, width: 1px, style: dashed } } selectonFileSelect deleteonFileDelete /关键配置说明参数类型说明推荐值auto-uploadBoolean关闭自动上传falsemodeString显示模式grid为九宫格gridlimitNumber最大选择数量根据需求image-stylesObject自定义图片样式适配UI设计2.2 实现多文件队列管理选择文件后我们需要维护一个上传队列data() { return { fileQueue: [], // 待上传文件队列 uploading: false, // 上传状态标志 progress: 0, // 整体进度 uploadedFiles: [] // 已上传文件列表 } }, methods: { onFileSelect(e) { const newFiles e.tempFiles.map(file ({ path: file.path, name: file.name, size: file.size, status: pending })) this.fileQueue [...this.fileQueue, ...newFiles] this.$refs.uploadBtn.show() // 显示上传按钮 } }提示对于大文件建议在上传前进行压缩处理。可以使用uni.compressImage API实现客户端压缩。3. 高级上传控制策略3.1 分片上传实现大文件支持对于超过5MB的文件建议实现分片上传async uploadInChunks(file, chunkSize 1024 * 1024) { const fileSize file.size let offset 0 const chunkCount Math.ceil(fileSize / chunkSize) while (offset fileSize) { const chunk file.slice(offset, offset chunkSize) const formData new FormData() formData.append(file, chunk) formData.append(chunkIndex, Math.floor(offset / chunkSize)) formData.append(totalChunks, chunkCount) formData.append(fileId, file.id) try { await this.uploadChunk(formData) offset chunkSize this.updateProgress(file.id, offset / fileSize * 100) } catch (error) { console.error(分片上传失败:, error) throw error } } return this.confirmUploadComplete(file.id) }3.2 并发控制与错误处理合理控制并发数可以避免浏览器限制async startUpload() { const CONCURRENCY 3 // 并发数 this.uploading true while (this.fileQueue.length 0) { const currentBatch this.fileQueue.splice(0, CONCURRENCY) await Promise.all(currentBatch.map(file this.uploadFile(file).catch(error { console.error(文件${file.name}上传失败:, error) this.retryQueue.push(file) // 加入重试队列 }) )) } if (this.retryQueue.length) { this.fileQueue [...this.retryQueue] this.retryQueue [] await this.startUpload() // 自动重试 } this.uploading false }4. 用户体验优化实战4.1 实时进度反馈结合uni-app的进度提示uploadFile(file) { return new Promise((resolve, reject) { const task uni.uploadFile({ url: this.uploadUrl, filePath: file.path, name: file, formData: { userId: this.userId }, success: (res) { const data JSON.parse(res.data) if (data.code 200) { resolve(data) } else { reject(new Error(data.message)) } }, fail: reject, complete: () { uni.hideLoading() } }) task.onProgressUpdate((res) { this.updateFileProgress(file.id, res.progress) if (res.progress 100) { uni.showToast({ title: ${file.name}上传完成, icon: success }) } }) }) }4.2 文件预览与删除实现文件预览和删除功能methods: { previewFile(file) { if (file.type image) { uni.previewImage({ current: file.url, urls: this.uploadedFiles .filter(f f.type image) .map(f f.url) }) } else { uni.downloadFile({ url: file.url, success: (res) { const filePath res.tempFilePath uni.openDocument({ filePath, fileType: file.ext, showMenu: true }) } }) } }, async deleteFile(fileId) { try { await uni.request({ url: ${this.apiBase}/files/${fileId}, method: DELETE }) this.uploadedFiles this.uploadedFiles.filter( f f.id ! fileId ) } catch (error) { uni.showToast({ title: 删除失败, icon: error }) } } }5. 性能优化与调试技巧5.1 上传性能优化策略客户端压缩对图片进行质量压缩格式转换将HEIC等特殊格式转为通用格式缓存处理避免重复上传相同文件网络检测根据网络状况调整上传策略// 图片压缩示例 compressImage(file) { return new Promise((resolve) { uni.compressImage({ src: file.path, quality: 70, success: (res) { resolve({ ...file, path: res.tempFilePath, size: res.tempFileSize }) }, fail: () resolve(file) // 压缩失败仍返回原文件 }) }) }5.2 常见问题排查上传功能常见问题及解决方案问题现象可能原因解决方案选择文件后无反应超出size限制检查limit和size参数上传进度卡住网络不稳定实现断点续传后台接收不到文件name参数不匹配确认前后端字段名一致跨域问题缺少CORS配置配置服务器Access-Control-Allow-Origin在开发过程中我习惯使用Charles或Fiddler抓包工具分析上传请求可以清晰看到请求头、表单数据和服务器响应。

更多文章