pinia actions 处理文件上传与进度上报需封装 xmlhttprequest 实现进度监听,暴露 uploadprogress、isuploading 等响应式状态,并通过抽离 uploadfile 工具函数、管理 abortcontroller 生命周期及利用 $onaction 统一增强行为,构建可控的“触发→监听→更新→完成/失败”流程。

Pinia Actions 处理文件上传与进度上报,关键在于把 原生 XMLHttpRequest 或 fetch + FormData 的底层能力 封装进异步 Action,同时暴露可响应的进度状态,让组件能实时渲染上传进度条。它不是简单发个请求就完事,而是一整套“触发→监听→更新→完成/失败”的可控流程。
用原生 XMLHttpRequest 实现带进度监听的上传
fetch 不支持上传进度监听,必须用 XMLHttpRequest。Action 内应创建实例、绑定 upload.onprogress,并将进度值同步到 store 状态中:
- 在 store 中定义
uploadProgress: number(0–100)、isUploading: boolean、uploadError: string | null - Action 接收
file: File参数,构造FormData并 append 文件 - 手动创建
XMLHttpRequest,设置onprogress回调,计算并更新uploadProgress - 成功后重置进度,存入返回数据;失败时捕获
xhr.status和响应体,统一转为用户提示
封装成可复用的上传函数,再由 Action 调度
不要在 Action 里写重复的 xhr 模板代码。建议抽离为独立工具函数,例如 uploadFile(file: File, options?: { url: string, onProgress?: (percent: number) => void }):
- 该函数只负责网络层,返回
Promise - Action 中调用它,并通过
onProgress回调把百分比同步到 store:uploadFile(file, { onProgress: p => this.uploadProgress = p }) - 这样既保持 Action 轻量(专注状态流转),又便于单元测试和 Mock(比如 mock 返回固定进度流)
处理并发与取消:避免进度错乱
用户可能快速选择多个文件、或中途取消上传。需主动管理请求生命周期:
- 每个上传 Action 执行前,检查是否有正在进行的请求,若有则调用
xhr.abort()终止上一个 - store 中可加字段
abortController: AbortController | null,每次新上传时新建并覆盖 - 在
onError或onLoadEnd后清空 controller,防止内存泄漏 - 组件卸载时(如路由离开),可在
onUnmounted中显式 abort 当前请求
配合 $onAction 做统一上传行为增强
利用 Pinia 的 $onAction 对所有上传类 Action(如命名含 upload)做自动增强:
-
before阶段设store.isUploading = true,并记录开始时间 -
onError中识别AbortError或网络错误,区分提示“已取消”或“上传失败” -
after阶段统计耗时、上报成功事件,并自动重置uploadProgress = 0 - 避免每个 Action 重复写 loading 开关和日志,逻辑集中且不易遗漏










