Vue3 + Element Plus 文件上传实战:从零构建带预览与手动提交的企业级上传组件
最近在重构一个后台管理系统,文件上传功能几乎是每个项目都绕不开的环节。Element Plus 的 el-upload 组件虽然功能强大,但实际项目中总会遇到各种定制化需求:手动触发上传、图片预览、文件类型限制、大小校验,还有那个让人头疼的 Content-Type 问题。今天我就结合最近的项目实践,分享一套完整的解决方案。
很多开发者习惯直接用 action 属性配置后端接口,这种方式简单但不够灵活。当我们需要在用户选择文件后先进行本地校验,或者需要等待用户填写完表单再统一提交时,手动上传模式就显得尤为重要。而且,图片预览功能在管理系统中几乎是标配,用户需要在上传前就能看到图片内容,避免传错文件。
1. 环境搭建与基础配置
1.1 项目初始化与依赖安装
首先确保你已经有一个 Vue3 项目,如果还没有,可以使用 Vite 快速创建一个:
npm create vue@latest my-upload-project
cd my-upload-project
npm install
接下来安装 Element Plus 及其图标库:
npm install element-plus @element-plus/icons-vue
在 main.js 或 main.ts 中引入 Element Plus:
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
提示:如果你使用 TypeScript,建议同时安装
@types/node以获得更好的类型支持。
1.2 理解 el-upload 的核心属性
在开始编码前,我们先梳理一下 el-upload 的几个关键属性,这些属性决定了组件的行为模式:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
action |
string | - | 上传的地址,手动上传时可设为 "#" |
auto-upload |
boolean | true | 是否在选择文件后立即自动上传 |
http-request |
function | - | 自定义上传的实现,覆盖默认行为 |
file-list |
array | [] | 已上传的文件列表,支持双向绑定 |
on-change |
function | - | 文件状态改变时的回调 |
before-upload |
function | - | 上传文件前的钩子,可进行校验 |
list-type |
string | 'text' | 文件列表的展示类型 |
limit |
number | - | 允许上传文件的最大数量 |
这里有个常见的误区:很多人以为 before-upload 钩子在手动上传模式下不会触发。实际上,无论是否自动上传,before-upload 都会在执行上传操作时触发。区别在于,自动上传时选择文件后立即触发,手动上传时则在调用 submit() 方法时触发。
2. 手动上传模式的核心实现
2.1 基础组件结构搭建
我们先创建一个基础的图片上传组件,支持手动触发上传:
<template>
<div class="upload-container">
<el-upload
ref="uploadRef"
action="#"
:file-list="fileList"
:auto-upload="false"
:multiple="true"
:limit="9"
accept="image/*"
list-type="picture-card"
:on-change="handleFileChange"
:on-remove="handleRemove"
:before-upload="beforeUpload"
>
<el-icon><Plus /></el-icon>
<template #tip>
<div class="el-upload__tip">
支持上传 JPG、PNG 格式图片,单张不超过 2MB
</div>
</template>
</el-upload>
<div class="action-buttons">
<el-button type="primary" @click="handleSubmit" :loading="uploading">
确认上传
</el-button>
<el-button @click="handleClear">清空列表</el-button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Plus } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
const uploadRef = ref()
const fileList = ref([])
const uploading = ref(false)
const rawFiles = ref([]) // 存储原始文件对象
</script>
这个基础结构有几个关键点:
action="#"表示我们不使用默认的上传行为:auto-upload="false"关闭自动上传list-type="picture-card"使用卡片式布局,适合图片展示- 通过
ref获取组件实例,后续可以调用其submit()方法
2.2 文件状态管理与校验逻辑
文件校验是上传功能中至关重要的一环。我们需要在用户选择文件时进行即时校验,避免无效文件进入上传队列:
const handleFileChange = (file, files) => {
// file 是当前变化的文件,files 是当前所有文件
console.log('文件变化:', file.name, file.status)
// 存储原始文件对象,用于后续 FormData 构建
if (file.raw) {
const existingIndex = rawFiles.value.findIndex(f => f.uid === file.uid)
if (existingIndex === -1) {
rawFiles.value.push(file.raw)
}
}
// 实时更新文件列表
fileList.value = files
}
const beforeUpload = (file) => {
// 文件类型校验
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
if (!allowedTypes.includes(file.type)) {
ElMessage.error('只支持 JPG、PNG、GIF、WebP 格式的图片')
return false
}
// 文件大小校验(2MB)
const maxSize = 2 * 1024 * 1024
if (file.size > maxSize) {
ElMessage.error('图片大小不能超过 2MB')
return false

2万+

被折叠的 条评论
为什么被折叠?



