手机网站域名解析,北京网站建设大概需要多少钱,263企业邮箱入口 邮箱登录,中国建筑校园招聘官网Vue 3 文件上传组件实现详解
在实际的前端开发中#xff0c;文件上传是一个常见的需求#xff0c;尤其是在需要处理文档、图片或其他类型文件的应用中。Vue 3 结合 Element Plus UI 组件库为我们提供了一个简单且灵活的文件上传解决方案。在这篇文章中#xff0c;我们将详细…Vue 3 文件上传组件实现详解
在实际的前端开发中文件上传是一个常见的需求尤其是在需要处理文档、图片或其他类型文件的应用中。Vue 3 结合 Element Plus UI 组件库为我们提供了一个简单且灵活的文件上传解决方案。在这篇文章中我们将详细介绍一个文件上传组件的实现过程并解释每一部分的逻辑和功能。
项目背景
假设我们正在开发一个表单功能用户可以在表单中上传附件。这个附件可以是多种格式如 doc, pdf, jpg 等同时我们希望对上传的文件数量和大小进行限制。为了提高用户体验我们还需要实现文件的删除功能和实时的上传提示信息。
需求分析
文件类型和大小限制允许用户上传特定类型和大小的文件。上传进度管理能够在上传过程中显示状态信息。文件删除功能支持上传文件的删除。实时提示上传前后提供相应的提示信息如格式不正确、大小超限等。
组件实现
我们利用 el-upload 组件来实现文件上传功能。el-upload 是 Element Plus 提供的一个文件上传组件它集成了文件上传、进度条、错误处理等常见功能。
1. 模板部分template
templatediv classupload-fileel-uploadmultiple !-- 支持多文件上传 --:actionuploadFileUrl !-- 上传请求的地址 --:before-uploadhandleBeforeUpload !-- 上传前的文件校验 --:file-listfileList !-- 当前上传的文件列表 --:limitlimit !-- 上传文件数量限制 --:on-errorhandleUploadError !-- 上传失败的回调 --:on-exceedhandleExceed !-- 超出文件数量限制的回调 --:on-successhandleUploadSuccess !-- 上传成功的回调 --:show-file-listfalse !-- 不显示默认的文件列表 --:headersheaders !-- 上传请求的头部 --classupload-file-uploaderreffileUpload!-- 上传按钮 --el-button typeprimary sizemini iconUpload plain上传附件/el-button/el-upload!-- 上传提示 --div classel-upload__tip v-ifshowTip请上传template v-iffileSize 大小不超过 b stylecolor: #f56c6c{{ fileSize }}MB/b /templatetemplate v-iffileType 格式为 b stylecolor: #f56c6c{{ fileType.join(/) }}/b /template的文件/div!-- 文件列表展示 --transition-group classupload-file-list el-upload-list el-upload-list--text nameel-fade-in-linear tagulli :keyfile.uid classfilelistcont v-for(file, index) in fileListdiv classfilelistcont-namespan classel-icon-document {{ getFileName(file.name) }} /span/divdiv classele-upload-list__item-content-actionel-link :underlinefalse clickhandleDelete(index) typedanger删除/el-link/div/li/transition-group/div
/template2. 脚本部分script setup
script setup
import { getToken } from /utils/auth;// 接收外部传入的属性
const props defineProps({modelValue: [String, Object, Array], // 绑定的文件值支持字符串、数组或对象limit: { type: Number, default: 5 }, // 限制上传的文件数量fileSize: { type: Number, default: 5 }, // 限制单个文件的大小单位MBfileType: { type: Array, default: () [doc, xls, ppt, txt, pdf] }, // 允许的文件类型isShowTip: { type: Boolean, default: true } // 是否显示上传提示
});// 获取当前上下文中的代理对象便于调用全局方法
const { proxy } getCurrentInstance();
const emit defineEmits(); // 定义组件的自定义事件
const number ref(0); // 记录上传的文件数量
const uploadList ref([]); // 上传成功的文件列表
const baseUrl import.meta.env.VITE_APP_BASE_API; // 基础 URL接口地址
const uploadFileUrl ref(import.meta.env.VITE_APP_BASE_API /upload); // 上传文件的接口
const headers ref({ Authorization: Bearer getToken() }); // 请求头带上认证 token
const fileList ref([]); // 当前选择的文件列表
const showTip computed(() props.isShowTip (props.fileType || props.fileSize)); // 控制是否显示上传提示信息// 监听 props.modelValue 的变化并同步更新文件列表
watch(() props.modelValue, val {if (val) {let temp 1;// 将传入的文件值转换为数组格式const list Array.isArray(val) ? val : props.modelValue.split(,);// 将文件数组转换为对象数组包含文件的名称和 URL 等信息fileList.value list.map(item {if (typeof item string) {item { name: item, url: item };}item.uid item.uid || new Date().getTime() temp; // 为每个文件生成唯一的 uidreturn item;});} else {fileList.value []; // 清空文件列表}
}, { deep: true, immediate: true });// 上传前进行文件的类型和大小校验
function handleBeforeUpload(file) {// 校验文件类型if (props.fileType.length) {const fileName file.name.split(.);const fileExt fileName[fileName.length - 1]; // 获取文件扩展名const isTypeOk props.fileType.indexOf(fileExt) 0;if (!isTypeOk) {proxy.$modal.msgError(文件格式不正确, 请上传${props.fileType.join(/)}格式文件!);return false; // 阻止上传}}// 校验文件大小if (props.fileSize) {const isLt file.size / 1024 / 1024 props.fileSize; // 判断文件大小是否小于限制值if (!isLt) {proxy.$modal.msgError(上传文件大小不能超过 ${props.fileSize} MB!);return false; // 阻止上传}}proxy.$modal.loading(正在上传文件请稍候...); // 显示上传中的提示number.value; // 增加上传文件数量return true; // 允许上传
}// 处理文件数量超出限制时的操作
function handleExceed() {proxy.$modal.msgError(上传文件数量不能超过 ${props.limit} 个!);
}// 处理上传失败的情况
function handleUploadError(err) {proxy.$modal.msgError(上传文件失败);
}// 处理上传成功的回调
function handleUploadSuccess(res, file) {if (res.url) {uploadList.value.push({ name: /profile/ res.path res.filename, url: res.url }); // 保存文件的 URL 和路径uploadedSuccessfully(); // 上传成功后的处理} else {number.value--; // 上传失败减去上传计数proxy.$modal.closeLoading(); // 关闭加载提示proxy.$modal.msgError(res.msg); // 显示错误信息proxy.$refs.fileUpload.handleRemove(file); // 移除上传失败的文件uploadedSuccessfully(); // 上传失败后的处理}
}// 处理文件删除
function handleDelete(index) {fileList.value.splice(index, 1); // 从文件列表中移除选中的文件emit(update:modelValue, listToString(fileList.value)); // 更新父组件的文件列表
}// 上传成功后处理文件列表和状态的更新
function uploadedSuccessfully() {if (number.value 0 uploadList.value.length number.value) {// 合并上传成功的文件与原始文件列表并更新 fileListfileList.value fileList.value.filter(f f.url ! undefined).concat(uploadList.value);uploadList.value []; // 清空上传列表number.value 0; // 重置上传计数emit(update:modelValue, listToString(fileList.value)); // 更新父组件的文件列表proxy.$modal.closeLoading(); // 关闭加载提示}
}
// 获取文件名避免 URL 显示
function getFileName(name) {if (name.lastIndexOf(/) -1) {return name.slice(name.lastIndexOf(/) 1); // 获取文件名去掉路径部分} else {return name; // 如果没有路径直接返回文件名}
}// 将文件列表转换为字符串以逗号分隔
function listToString(list, separator) {let strs ;separator separator || ,; // 默认使用逗号分隔for (let i in list) {if (list[i].url) {strs list[i].url separator; // 拼接 URL 字符串}}return strs ! ? strs.substr(0, strs.length - 1) : ; // 去掉最后一个分隔符
}
/script3. 样式部分
style scoped
.upload-file {position: relative;
}
.upload-file .filelistcont {display: flex;align-items: center;justify-content: space-between;padding: 8px 12px;border: 1px solid #dcdfe6;margin-bottom: 8px;border-radius: 4px;
}
.upload-file .filelistcont-name {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
}
.el-upload__tip {margin-top: 12px;font-size: 12px;color: #999;
}
/style总结
通过结合 Vue 3 的响应式特性和 Element Plus 的 el-upload 组件我们实现了一个功能完善的文件上传组件。这个组件不仅支持文件的上传、校验和删除还提供了上传进度提示和错误处理。通过自定义的事件机制我们可以将文件列表从子组件传递到父组件确保数据的同步和状态管理。
在实际开发中根据不同的需求组件的功能可以进一步扩展比如支持上传进度条、拖拽上传、批量处理等。希望通过这篇文章你能深入理解 Vue 3 文件上传组件的实现并能够在自己的项目中灵活应用。