Pinia不直接处理文件上传,但可通过store管理上传状态、进度和结果;需在state中定义isUploading、progress等字段,在actions中用axios.onUploadProgress监听进度,并在组件中响应式展示。

Pinia 本身不直接处理文件上传,但它非常适合管理上传过程中的进度、状态和结果。关键在于把上传逻辑(如 fetch 或 axios 请求)放在 Store 的 actions 中,并用 state 实时记录进度、错误、完成状态等信息。
定义上传相关的 state 字段
在 Store 中明确声明与上传生命周期相关的响应式字段:
- isUploading:布尔值,标识是否正在上传
- progress:数字(0–100),表示当前上传进度百分比
- uploadId(可选):用于关联请求或取消上传
- error:字符串或 null,存储失败原因
- result(可选):上传成功后返回的数据,如服务器返回的文件 URL
在 actions 中实现带进度监听的上传逻辑
利用 XMLHttpRequest 或 fetch + ReadableStream(需浏览器支持)监听进度;更常用且兼容性好的方式是封装一个基于 XMLHttpRequest 的上传函数,或使用 axios 的 onUploadProgress 钩子。
示例(使用 axios):
import { defineStore } from 'pinia'
import axios from 'axios'
<p>export const useUploadStore = defineStore('upload', {
state: () => ({
isUploading: false,
progress: 0,
error: null,
result: null,
}),
actions: {
async uploadFile(file) {
this.isUploading = true
this.progress = 0
this.error = null</p><pre class="brush:php;toolbar:false;"> try {
const formData = new FormData()
formData.append('file', file)
await axios.post('/api/upload', formData, {
onUploadProgress: (e) => {
if (e.total) {
this.progress = Math.round((e.loaded / e.total) * 100)
}
},
})
this.result = { message: '上传成功' }
} catch (err) {
this.error = err.response?.data?.message || '上传失败'
} finally {
this.isUploading = false
}
},}, })
组件中调用与响应式展示
在组件中使用时,注意保持响应性 —— 不要直接解构 state 字段,而是用 storeToRefs 或直接访问属性:
<script setup>
import { storeToRefs } from 'pinia'
import { useUploadStore } from '@/stores/upload'
<p>const uploadStore = useUploadStore()
const { isUploading, progress, error, result } = storeToRefs(uploadStore)
</script></p><p><template>
<input type="file" @change="e => uploadStore.uploadFile(e.target.files[0])" />
<div v-if="isUploading">上传中:{{ progress }}%</div>
<div v-else-if="error">错误:{{ error }}</div>
<div v-else-if="result">{{ result.message }}</div>
</template>进阶:支持取消上传与多文件队列
如需取消,可结合 AbortController(axios 支持 signal)并在 action 中暴露 cancel 方法;多文件场景建议将 state 设计为数组或 Map,每个上传任务独立维护状态,避免互相干扰。


















