后台项目里面上传功能也很常见,头像、封面、附件、合同文件都可能会用到,所以这里记录一下 Vue3 中上传组件的封装
上传看起来只是选择文件,但是在真实项目里面会遇到很多细节。
比如:
- 单图上传
- 多图上传
- 文件上传
- 上传数量限制
- 新增时清空
- 编辑时回填
- 保存时字段格式统一
所以我这次在后台模板里面整理了图片上传和文件上传两个组件。
图片上传
图片上传使用的是 UploadImgMore。
单图上传:
1 2 3 4 5 6 7 8 9
| <UploadImgMore ref="singleUploadRef" mock-upload :more-length="1" :upload-type="1" :input-width="118" :input-height="118" @updataImg="updateSingleImg" />
|
多图上传:
1 2 3 4 5 6 7 8 9 10
| <UploadImgMore ref="multiUploadRef" mock-upload multiple :more-length="4" :upload-type="1" :input-width="94" :input-height="94" @updataImg="updateMultiImg" />
|
这里几个参数比较常用:
more-length:最多上传几个
multiple:是否支持多选
input-width:上传框宽度
input-height:上传框高度
mock-upload:模板演示时使用 mock 上传
文件上传
文件上传使用的是 UploadFile。
1 2 3 4 5 6 7 8
| <UploadFile ref="fileUploadRef" mock-upload :more-length="2" @updataImg="updateFileList" > 支持文档、压缩包、安装包等附件示例。 </UploadFile>
|
文件上传和图片上传最后都统一返回文件列表。
统一字段
不同上传组件或者不同后端返回的字段可能不一样。
有的叫 url,有的叫 oss_url。
有的叫 name,有的叫 oss_key。
所以保存前最好统一一下字段:
1 2 3 4 5 6
| normalizeUploadList(fileList = []) { return fileList.map((item) => ({ oss_key: item.oss_key || item.name, oss_url: item.oss_url || item.url })); }
|
这样后面业务保存的时候,就不用关心组件内部返回了什么字段。
新增
新增时需要把表单和上传组件都清空。
1 2 3 4 5 6 7 8 9
| openCreate() { this.formData = createDefaultForm(); this.createDialog = true;
this.$nextTick(() => { this.resetDialogUpload(); this.$refs.formRef?.clearValidate(); }); }
|
这里需要等弹窗打开之后再调用组件方法,所以放在 $nextTick 中。
编辑回填
编辑时最重要的是回填。
表单数据可以直接复制,但是上传组件里面的文件列表需要手动初始化。
1 2 3 4 5 6 7 8 9 10 11
| edit(row) { this.formData = JSON.parse(JSON.stringify(row)); this.createDialog = true;
this.$nextTick(() => { this.$refs.dialogCoverRef?.initUpload(this.formData.coverList); this.$refs.dialogImagesRef?.initUpload(this.formData.imageList); this.$refs.dialogFileRef?.initFile(this.formData.fileList); this.$refs.formRef?.clearValidate(); }); }
|
图片使用 initUpload,文件使用 initFile。
这样打开编辑弹窗时,之前上传过的图片和文件就能正常显示出来。
重置组件
弹窗关闭时也需要重置上传组件。
1 2 3 4 5
| resetDialogUpload() { this.$refs.dialogCoverRef?.resetFields(); this.$refs.dialogImagesRef?.resetFields(); this.$refs.dialogFileRef?.resetFields(); }
|
不然可能会出现新增时还显示上一次编辑图片的问题。
表单校验
如果封面图是必填,可以把上传结果放进表单字段里。
1 2 3 4
| updateDialogCover(fileList) { this.formData.coverList = this.normalizeUploadList(fileList); this.$refs.formRef?.validateField('coverList'); }
|
上传后主动触发表单校验,这样用户上传图片后错误提示能及时消失。
保存
保存的时候只保存整理后的字段。
1 2 3 4 5 6 7 8 9 10 11
| save() { this.$refs.formRef.validate((valid) => { if (!valid) { return; }
const data = JSON.parse(JSON.stringify(this.formData));
// 调接口保存 data }); }
|
真实项目里面这里换成接口请求就可以了。
mock上传
模板里面加了 mock-upload,主要是为了让示例页面不依赖真实接口。
新项目接入真实后端时,可以去掉 mock-upload,然后在上传组件里面接入真实的 OSS token 或上传接口。
总结
上传组件封装时,我觉得最容易忽略的是编辑回填。
只处理新增上传不难,难的是保证下面几件事都正常:
- 新增时为空
- 编辑时能回填
- 删除后字段同步
- 上传后表单校验同步
- 保存字段格式统一
这些处理好以后,图片上传、附件上传、封面上传这些场景基本都能复用。
以上就是我对 Vue3 上传组件封装的一些理解,如有错误,欢迎大佬指出。