Vue 3 和 React 实现单文件与多文件上传
文件上传在前端里算是高频功能,但真正落地时,麻烦往往不在'选文件'这一步,而在限制大小、控制上传时机、显示进度、拖拽交互和后端字段对接这些细节上。组件库能省不少事,原生方案则更适合你想把流程握在自己手里时用。
一、Vue 3 原生实现
1.1 单文件上传
先用最直接的方式把流程跑通。
<template>
<div>
<!-- 文件选择框 -->
<input type="file" @change="handleFile" />
<!-- 上传按钮 -->
<button @click="upload" :disabled="!file">上传</button>
<!-- 预览文件名 -->
<p v-if="file">已选择:{{ file.name }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const file = ref(null)
// 监听文件选择事件
const handleFile = (e) => {
file.value = e.target.files[0]
}
// 上传文件到服务器
const upload = async () => {
if (!file.value) return
const formData = new FormData()
formData.append('file', file.value)
await fetch('/api/upload', {
method: 'POST',
body: formData
})
}
</script>
这里最容易忽略的点有两个:e.target.files[0] 只取第一个文件;FormData 会自己处理 Content-Type 的边界值,不用手动补。
1.2 多文件上传
多文件上传和单文件的差别不大,核心是把文件列表收好,再按后端能识别的字段名逐个塞进 FormData。
<template>
<div>
<input type="file" multiple @change="handleFiles" />
<button @click="upload" :disabled="!files.length">批量上传</button>
<ul>
<li v-for="f in files" :key="f.name">{{ f.name }}</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue'
const files = ref([])
// 获取选中的多个文件
const handleFiles = (e) => {
files.value = Array.from(e.target.files)
}
// 批量上传多个文件
const upload = async () => {
if (!files.value.length) return
const formData = new FormData()
// 注意:这里要用相同的字段名 'files',后端才能用 List/MultipartFile[] 接收
files.value.forEach(f => formData.append('files', f))
await fetch('/api/upload/multiple', {
method: 'POST',
body: formData
})
}
</script>
前端 append 的字段名要和后端参数名对上,这个地方一旦不一致,接口通常不会报得很直白,只会让你看半天空数组。
二、Vue 3 + Element Plus 实现
组件库的价值很现实:少写样式,少管交互细节,先把业务做完。
2.1 单文件上传
<template>
<el-upload action="/api/upload" :on-success="handleSuccess" :on-error="handleError" :show-file-list="false">
<el-button type="primary">选择文件</el-button>
</el-upload>
</template>
<script setup>
// 上传成功回调
const handleSuccess = (res) => {
ElMessage.success('上传成功')
}
// 上传失败回调
const handleError = () => {
ElMessage.error('上传失败')
}
</script>
action 是必填项,:show-file-list="false" 则是把默认列表藏掉。页面上如果只想保留一个按钮,这个属性很顺手。

