一、问题背景**
- 背景:使用element的上传组件,在使用多文件上传时,发现如果同时选择两个文件,上传完成之后,upload组件的列表只显示一个文件。
- 通过查看控制台发现on-success方法在上传文件时,只执行了一次。返回的两个文件,其中一个状态是uploading。而我们取文件又只取了status是success的文件。
二、探索和解决**
1,解除绑定upload组件的file-list绑定(非根本解决)
这个方法简单粗暴,通过自己验证确实是可以的。不会出现选择多个文件上传,最后只有一个生效的问题。但是这个解决方法有个弊端就是说,当我们需要数据回显时,upload组件的flie-list并没有绑定数据,所以不会渲染出来。
2,通过绑定初始变量,实际操作使用另一个变量(根本解决);
第二种方法是:我们可以通过定义两个变量:
一个赋初值给upload组件,仅仅只是作为展示使用;
一个是真实我们要操控的变量,所有的对于文件的操作,包括上传和删除都对这个变量进行操作
贴一下关键代码
<template>
<el-dialog :title="title" :visible.sync="dialogVisible" width="60%">
<upload-file
type="file"
:upload-success="uploadSuccess"
:remove="updateFileList"
:file-list="fileList"
:limit-count="5"
:limit-size="10"
ref="uploadFile"
></upload-file>
</el-dialog>
</template>
<script>
import { MESSAGE_API } from '@/api';
import UploadFile from '@/components/upload-file';
export default {
name: 'property-dialog',
model: {
prop: 'dialogVisible',
event: 'change'
},
components: {
UploadFile
},
props: {
dialogVisible: {
type: Boolean,
default: false
},
options: {
type: Object,
default: () => ({})
}
},
data() {
return {
fileList: [], //fileList仅仅作为展示使用
realFileList: [] // 所有关于文件的上传和删除直接操作 realFileList。
};
},
methods: {
dialogCancel() {
this.$emit('change', false);
},
updateFileList(file) {
// 剔除被删除的文件
this.realFileList = this.realFileList.filter(v => v.path !== file.path);
},
async uploadSuccess(result, file) {
// 对于上传成功的文件 只保存到realFileList
if (result.success) {
const { fileName, path, fileSize } = file.response.data;
const fileObj = {
fileName,
path,
fileSize,
name: fileName
};
this.realFileList.push(fileObj);
}
},
async dialogSubmit(){
// 提交文件 attachments 也是提交 realFileList
const attachments = this.realFileList;
console.log(`attachments`, attachments)
this.$emit('change', false);
},
async getDetail(){
const { id, areaCode, appCode } = this.options.colum;
const result = await MESSAGE_API.getEmailDetail({ id, areaCode, appCode });
const { attachmentRequest } = result.data;
// 获取数据对两个文件列表都进行赋值
this.fileList = attachmentRequest ? attachmentRequest.attachments.map(v => ({ ...v, name: v.fileName })) : [];
this.realFileList = attachmentRequest ? attachmentRequest.attachments.map(v => ({ ...v, name: v.fileName })) : [];
}
}
};
</script>
封装的upload组件,如果需要可以自取
<template lang="html">
<div class="upload-file">
<el-upload
:action="url"
:headers="headers"
:before-upload="beforeUpload"
:on-success="uploadSuccess"
:on-preview="isPicture ? onPreview : download"
:on-remove="remove"
:before-remove="beforeRemove"
:on-exceed="onExceed"
:list-type="listType"
:accept="accept"
:file-list="fileList"
:limit="limitCount"
:disabled="disabled"
:class="[isHideUpload && 'hide-upload-button', disabled && 'operate-disabled', uploadClassName]"
multiple
ref="elUpload"
>
<template v-if="isPicture">
<i class="el-icon-plus"></i>
</template>
<template v-else>
<el-button :disabled="disabled" size="small" type="primary">{{uploadText}}</el-button>
</template>
<div slot="tip" class="el-upload__tip">{{ tip }}</div>
</el-upload>
<image-viewer-s v-show="dialogVisible" :on-close="closeViewer" :url-list="[dialogImageUrl]"></image-viewer-s>
</div>
</template>
<script>
import Cookies from 'js-cookie';
const API_HOST = process.env.VUE_APP_API_HOST;
const PREFIX = process.env.VUE_APP_PUBLIC_API_EMAIL_PREFIX;
const APP_CODE = process.env.VUE_APP_APP_CODE;
const TOKEN_KEY = process.env.VUE_APP_TOKEN_KEY;
export default {
name: 'upload-file',
props: {
type: {
type: String,
default: 'file' // file/picture
},
limitCount: {
type: Number,
default: 1
},
limitSize: {
type: Number,
default: 5 // 单位 M
},
fileList: {
type: Array,
default: () => ([])
},
uploadSuccess: {
type: Function,
default: () => {}
},
remove: {
type: Function,
default: () => {}
},
download: {
type: Function,
default: () => {}
},
previewImg: {
type: Function,
default: () => {}
},
tip: {
type: String,
default: ''
},
uploadClassName: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
uploadText: {
type: String,
default: '+ Upload'
}
},
data() {
return {
url: `${API_HOST}${PREFIX}/file/uploadFile`,
dialogImageUrl: '',
dialogVisible: false
};
},
computed: {
headers() {
return {
Authorization: Cookies.get(TOKEN_KEY),
appCode: APP_CODE
};
},
isPicture() {
return this.type === 'picture';
},
accept() {
return this.isPicture ? 'image/*' : '';
},
listType() {
return this.isPicture ? 'picture-card' : 'text';
},
isHideUpload() {
return this.fileList.length >= this.limitCount;
}
},
methods: {
onExceed(files, fileList) {
this.$message.warning(`No more than ${ this.limitCount } files, you have selected ${files.length} files, total ${files.length + fileList.length} files`);
},
async onPreview(file) {
const { url } = file;
if (url.includes('base64')) {
this.dialogImageUrl = url;
} else {
this.dialogImageUrl = await this.previewImg(file.response.data);
}
this.dialogVisible = true;
},
beforeUpload(file) {
const { size } = file;
if (this.isOverSize(size)) {
this.$message.error(`The file size is ${(size / 1024 / 1024).toFixed(2)}M,over ${this.limitSize}M`);
return false;
}
},
beforeRemove(file) {
const { size } = file;
if (!this.isOverSize(size)) {
return this.$confirm(`Delete ${ file.name }?`);
}
},
isOverSize(size) {
if (size / 1024 / 1024 < this.limitSize) {
return false;
}
return true;
},
closeViewer() {
this.dialogVisible = false;
},
clearFiles() {
this.$refs.elUpload.clearFiles();
}
}
};
</script>
<style lang="scss" scoped>
.upload-file {
.operate-disabled {
/deep/.el-upload--picture-card {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #C0C4CC;
cursor: not-allowed;
&:hover,
&:focus {
border-color: #E4E7ED;
}
}
}
}
</style>
三、总结
问题的解决是一个探索的过程。当然这么说也有点问题,实际的方案并不是自己出的,而是通过求助网友。自己只是把问题的解决方案拿出来,分享给大家,互助共赢。感谢这个大佬。
https://blog.csdn.net/qq_41780372/article/details/117773863