Wot Design Uni 文件上传组件:如何实现异步上传的强大功能 Wot Design Uni 文件上传组件如何实现异步上传的强大功能【免费下载链接】wot-design-uni一个基于Vue3TS开发的uni-app组件库提供70高质量组件支持暗黑模式、国际化和自定义主题。项目地址: https://gitcode.com/gh_mirrors/wo/wot-design-uni在现代移动应用开发中文件上传是一个复杂但至关重要的功能。Wot Design Uni 作为一款基于 Vue3TS 开发的 uni-app 组件库其 wd-upload 组件提供了强大且灵活的异步上传解决方案。本文将深入探讨如何利用 wd-upload 的异步上传功能实现复杂的业务需求。为什么需要异步上传功能在真实业务场景中文件上传往往不只是简单的文件传输。开发者通常需要在文件上传前进行一系列预处理操作文件格式转换- 如 HEIC 转 JPG、视频转码等文件大小校验- 检查文件是否超过限制内容安全检查- 扫描文件内容是否安全后端接口验证- 验证用户权限或配额分片上传准备- 大文件分片上传的前置处理Wot Design Uni 的 wd-upload 组件通过支持 Promise 类型的upload-method属性让这些异步处理变得简单而优雅。异步上传的核心实现原理让我们深入源码看看 wd-upload 如何实现异步上传支持// 在 useUpload.ts 中的关键实现 const startUpload (file: UploadFileItem, options: UseUploadOptions) { const { uploadMethod } options const uploadOptions { action, header, name, fileName: name, fileType, statusCode, abortPrevious, onSuccess: (res, file, formData) { file[statusKey] UPLOAD_STATUS.SUCCESS currentTask null options.onSuccess?.(res, file, formData) }, onError: (error, file, formData) { file[statusKey] UPLOAD_STATUS.FAIL file.error error.errMsg currentTask null options.onError?.(error, file, formData) }, onProgress: (res, file) { file.percent res.progress options.onProgress?.(res, file) } } // 关键代码支持自定义上传方法 if (isFunction(uploadMethod)) { return uploadMethod(file, formData, uploadOptions) } else { return defaultUpload(file, formData, uploadOptions) } }组件内部通过isFunction(uploadMethod)判断是否传入了自定义上传函数如果传入了则调用该函数并传递完整的配置选项。这种设计让开发者可以完全控制上传流程。实战构建异步上传处理链下面是一个完整的异步上传示例展示了如何处理复杂的业务逻辑template wd-upload v-model:file-listfileList :upload-methodcustomUpload :limit5 :max-size10 * 1024 * 1024 // 10MB changehandleChange successhandleSuccess failhandleError wd-button typeprimary custom-classupload-btn 上传文件 /wd-button /wd-upload /template script setup langts import { ref } from vue import type { UploadMethod, UploadFileItem } from /uni_modules/wot-design-uni const fileList refUploadFileItem[]([]) // 核心的异步上传函数 const customUpload: UploadMethod async (file, formData, options) { try { // 1. 文件类型校验 if (!isValidFileType(file)) { throw new Error(不支持的文件类型) } // 2. 文件大小校验虽然组件已有 max-size但这里可以做更复杂的校验 if (file.size 10 * 1024 * 1024) { throw new Error(文件大小超过10MB限制) } // 3. 异步压缩处理如果是图片 if (isImageFile(file)) { const compressedFile await compressImage(file) file compressedFile } // 4. 获取上传凭证异步接口调用 const uploadToken await getUploadToken() // 5. 调用后端上传接口 const result await uploadToServer(file, uploadToken, { onProgress: (progress) { // 手动触发进度更新 options.onProgress?.({ progress }, file) } }) // 6. 上传成功回调 options.onSuccess?.(result, file, formData) // 返回上传任务实例如果需要取消上传 return { abort: () { console.log(取消上传) } } } catch (error) { // 错误处理 options.onError?.({ errMsg: error.message || 上传失败 }, file, formData) throw error } } // 辅助函数 const isValidFileType (file: UploadFileItem): boolean { const allowedTypes [image/jpeg, image/png, application/pdf] return allowedTypes.includes(file.type || ) } const isImageFile (file: UploadFileItem): boolean { return file.type?.startsWith(image/) || false } const compressImage async (file: UploadFileItem): PromiseUploadFileItem { // 使用uni.compressImage进行图片压缩 return new Promise((resolve, reject) { uni.compressImage({ src: file.url, quality: 80, success: (res) { resolve({ ...file, url: res.tempFilePath, size: res.tempFileSize }) }, fail: reject }) }) } const getUploadToken async (): Promisestring { // 调用后端接口获取上传凭证 const response await uni.request({ url: /api/upload/token, method: GET }) return response.data.token } const uploadToServer async ( file: UploadFileItem, token: string, options: { onProgress?: (progress: number) void } ): Promiseany { return new Promise((resolve, reject) { const uploadTask uni.uploadFile({ url: https://api.example.com/upload, filePath: file.url, name: file, header: { Authorization: Bearer ${token}, Content-Type: multipart/form-data }, formData: { token, timestamp: Date.now() }, success: (res) { if (res.statusCode 200) { resolve(JSON.parse(res.data)) } else { reject(new Error(上传失败)) } }, fail: reject }) // 监听上传进度 uploadTask.onProgressUpdate((res) { options.onProgress?.(res.progress) }) }) } const handleChange ({ fileList }) { console.log(文件列表变化:, fileList) } const handleSuccess ({ file, fileList }) { console.log(上传成功:, file) } const handleError ({ error, file }) { console.error(上传失败:, error) uni.showToast({ title: 上传失败: ${error.errMsg}, icon: none }) } /script style scoped .upload-btn { width: 200rpx; height: 80rpx; } /style异步上传的进阶技巧1. 分片上传大文件对于大文件上传我们可以实现分片上传功能const chunkedUpload: UploadMethod async (file, formData, options) { const CHUNK_SIZE 1 * 1024 * 1024 // 1MB const totalChunks Math.ceil(file.size / CHUNK_SIZE) // 1. 获取上传ID const uploadId await getUploadId(file.name, file.size) // 2. 分片上传 for (let i 0; i totalChunks; i) { const start i * CHUNK_SIZE const end Math.min(start CHUNK_SIZE, file.size) const chunk await readFileChunk(file.url, start, end) await uploadChunk(uploadId, i, chunk, { onProgress: (progress) { const totalProgress ((i 1) / totalChunks) * 100 options.onProgress?.({ progress: totalProgress }, file) } }) } // 3. 合并分片 const result await mergeChunks(uploadId) options.onSuccess?.(result, file, formData) }2. 并发上传优化const concurrentUpload: UploadMethod async (file, formData, options) { const MAX_CONCURRENT 3 const uploadPromises [] // 创建多个上传任务 for (let i 0; i MAX_CONCURRENT; i) { uploadPromises.push(uploadFilePart(file, i)) } // 并发执行 const results await Promise.allSettled(uploadPromises) // 处理结果 const successfulUploads results.filter(r r.status fulfilled) if (successfulUploads.length 0) { options.onSuccess?.(successfulUploads[0].value, file, formData) } else { options.onError?.({ errMsg: 所有上传都失败 }, file, formData) } }3. 断点续传实现const resumeUpload: UploadMethod async (file, formData, options) { // 1. 检查是否有未完成的上传 const uploadRecord await checkUploadRecord(file) if (uploadRecord uploadRecord.chunks) { // 2. 继续上传未完成的块 const remainingChunks getRemainingChunks(uploadRecord.chunks) for (const chunk of remainingChunks) { try { await uploadChunkWithRetry(chunk, { maxRetries: 3, onProgress: (progress) { const totalProgress calculateTotalProgress(uploadRecord, progress) options.onProgress?.({ progress: totalProgress }, file) } }) // 3. 更新上传记录 await updateUploadRecord(file, chunk) } catch (error) { console.error(分片上传失败:, error) throw error } } } else { // 4. 开始新的上传 return startNewUpload(file, formData, options) } }错误处理与调试技巧1. 完善的错误处理const robustUpload: UploadMethod async (file, formData, options) { try { // 1. 网络状态检查 if (!navigator.onLine) { throw new Error(网络连接不可用) } // 2. 重试机制 let retries 3 while (retries 0) { try { return await attemptUpload(file, formData, options) } catch (error) { retries-- if (retries 0) throw error await sleep(1000 * (4 - retries)) // 指数退避 } } } catch (error) { // 3. 错误分类处理 if (error.message.includes(network)) { options.onError?.({ errMsg: 网络错误请检查连接 }, file, formData) } else if (error.message.includes(timeout)) { options.onError?.({ errMsg: 上传超时请重试 }, file, formData) } else { options.onError?.({ errMsg: error.message }, file, formData) } } }2. 调试日志const debugUpload: UploadMethod async (file, formData, options) { console.group( 文件上传调试信息) console.log(文件信息:, { name: file.name, size: formatFileSize(file.size), type: file.type, url: file.url }) console.log(上传配置:, { action: options.action, headers: options.header, formData }) try { const startTime Date.now() const result await uploadFile(file, formData, options) const endTime Date.now() console.log(上传结果:, result) console.log(上传耗时:, ${endTime - startTime}ms) console.groupEnd() return result } catch (error) { console.error(上传错误:, error) console.groupEnd() throw error } }性能优化建议1. 图片压缩优化const optimizeImageUpload async (file: UploadFileItem): PromiseUploadFileItem { // 根据设备像素比和网络状况动态调整压缩质量 const devicePixelRatio uni.getSystemInfoSync().pixelRatio const networkType uni.getNetworkTypeSync().networkType let quality 80 // 默认质量 if (networkType wifi) { quality 90 // WiFi环境下使用高质量 } else if (networkType 4g) { quality 75 // 4G网络使用中等质量 } else { quality 60 // 其他网络使用低质量 } // 高分辨率设备适当降低质量 if (devicePixelRatio 2) { quality Math.max(60, quality - 10) } return compressImageWithQuality(file, quality) }2. 上传队列管理class UploadQueue { private queue: Array() Promisevoid [] private concurrent 0 private maxConcurrent 3 async add(uploadTask: () Promisevoid) { this.queue.push(uploadTask) await this.processQueue() } private async processQueue() { while (this.concurrent this.maxConcurrent this.queue.length 0) { this.concurrent const task this.queue.shift()! task() .catch(error { console.error(上传任务失败:, error) }) .finally(() { this.concurrent-- this.processQueue() }) } } } // 使用队列管理上传 const uploadQueue new UploadQueue() const queuedUpload: UploadMethod async (file, formData, options) { return new Promise((resolve, reject) { uploadQueue.add(async () { try { const result await defaultUpload(file, formData, options) resolve(result) } catch (error) { reject(error) } }) }) }最佳实践总结合理使用异步钩子充分利用before-upload、before-choose等钩子函数进行预处理实现完善的错误处理包括网络错误、文件错误、服务器错误等添加进度反馈通过onProgress回调提供实时上传进度支持取消操作实现上传任务的取消功能添加重试机制网络不稳定时的自动重试优化用户体验根据网络状况调整上传策略结语Wot Design Uni 的 wd-upload 组件通过支持 Promise 类型的异步上传函数为开发者提供了极大的灵活性。无论是简单的文件上传还是复杂的业务场景都可以通过自定义的upload-method来实现。通过本文的深入分析相信你已经掌握了如何充分利用 wd-upload 的异步上传功能。在实际开发中结合具体业务需求你可以构建出更加强大、稳定的文件上传解决方案。记住好的上传体验不仅仅是技术实现更是对用户需求的深度理解。Wot Design Uni 为你提供了强大的工具剩下的就是发挥你的创造力构建出优秀的用户体验。【免费下载链接】wot-design-uni一个基于Vue3TS开发的uni-app组件库提供70高质量组件支持暗黑模式、国际化和自定义主题。项目地址: https://gitcode.com/gh_mirrors/wo/wot-design-uni创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考