el-upload 第一次上传失败,无法再次上传,二次上传无效

1. 业务场景

使用 Element 的 upload 上传组件,手动上传文件失败,再次点击无效。
特别是上传之前,整个页面加了 loading,这时候的体验就非常不好。

<template>
	<el-upload
		ref="upload"
		:limit="1"
		accept=".xlsx"
		:action="$baseUrl + '/api/xxx'"
		:headers="headers"
		:auto-upload="false"
		:on-success="handleSuccess"
		:on-error="handleError"
		:on-exceed="handleExceed"
	>
		<el-button icon="el-icon-folder-opened" size="mini">
			选取文件
		</el-button>
	</el-upload>
	<el-button
		type="primary"
		icon="el-icon-upload"
		size="mini"
		:loading="loading.upload"
		@click="btn_submit"
	>
		上传
	</el-button>
</template>
<script>
export default {
	data() {
		retutn {
			loading: { upload: false },
			headers: { Authorization: "Bearer " + getToken() },
		}
	},
	methods: {
		btn_submit() {
			const upload = this.$refs.upload;
			/** 文件校验 */
			...
			this.loading.upload = true;
			upload.submit(); // 提交
		},
		/** 文件超出个数限制时的钩子 */
		handleExceed(file, fileList) {
			this.$message.warning("超出文件上传数量限制");
		},
		/** 文件上传成功时的钩子 */
		handleSuccess(res, file, fileList) {
			this.loading.upload = false;
			if(res.code == 200) {
				...
				this.$message.success("文件上传成功");
			} else {
				file.status = "fail";
        		this.$message.error(res.msg || "文件上传失败");
			}
		},
		/** 文件上传失败时的钩子 */
		handleError(err, file, fileList) {
			this.loading.upload = false;
        	this.$message.error("文件上传失败");
		},
	}
}
</script>

2. 解决方案

2.1 省去上传步骤,直接提示失败。

我们可以把首次的失败信息用一个字段 upfilefail 保存下来,如果 upfilefail 不为空,就说明已经提交并且失败了,这时直接抛出错误提示。
然后文件移除的时候,需要把 upfilefail 置空。

btn_submit() {
	const upload = this.$refs.upload;
	/** 文件校验 */
	...
	// 首次正常提交
	if(!this.upfilefail) {
		this.loading.upload = true;
		upload.submit(); // 提交
	}
	// 提交失败之后,直接抛出错误提示
	else {
		this.$message.error(this.upfilefail);
	}
},
/** 文件上传成功时的钩子 */
handleSuccess(res, file, fileList) {
	this.loading.upload = false;
	if(res.code == 200) {
		...
		this.$message.success("文件上传成功");
	} else {
		file.status = "fail";
		this.upfilefail = res.msg || "文件上传失败";
		this.$message.error(this.upfilefail);
	}
},
/** 文件上传失败时的钩子 */
handleError(err, file, fileList) {
	this.loading.upload = false;
	this.upfilefail = "文件上传失败";
	this.$message.error(this.upfilefail);
},
/** 文件列表移除文件时的钩子 */
handleRemove(file, fileList) {
	this.upfilefail = ""; // 文件移除,文件上传失败信息置空
},

2.2 重置状态,重新上传

如果我们确实有重新上传的需求怎么办呢?

但直接二次上传是无效的,因为文件列表中没有新的文件,已有的文件状态都是已上传,所以不会再次走上传流程。
为了更好理解,我们直接上源码,简单了解一下上传流程!

    1. 选取文件的时候,会调用一个 handleStart 的方法对文件进行格式化。

element-ui/packages/upload/index.vue

handleStart(rawFile) {
  rawFile.uid = Date.now() + this.tempIndex++;
  let file = {
    status: 'ready',
    name: rawFile.name,
    size: rawFile.size,
    percentage: 0,
    uid: rawFile.uid,
    raw: rawFile
  };
  if (this.listType === 'picture-card' || this.listType === 'picture') {
    try {
      file.url = URL.createObjectURL(rawFile);
    } catch (err) {
      console.error('[Element Error][Upload]', err);
      return;
    }
  }
  this.uploadFiles.push(file);
  this.onChange(file, this.uploadFiles);
}

选择的文件都放在了 uploadFiles 中,这时文件状态是 ready

    1. 调用组件的 submit 方法

element-ui/packages/upload/index.vue

submit() {
  this.uploadFiles
    .filter(file => file.status === 'ready')
    .forEach(file => {
      this.$refs['upload-inner'].upload(file.raw);
    });
}

文件提交的时候,会先把文件列表中 ready 状态的文件过滤出来。
更具体的上传过程在 upload.vue 中,这里就不过多展开了。
OK,这两步就已经能大致看出问题了。

补充:其他几种文件状态

file.status = 'uploading';	// 上传中
file.status = 'success';	// 上传成功
file.status = 'fail';		// 上传失败

所以我们要重新上传文件走接口的话,需要我们手动重置一下文件状态。

btn_submit() {
	const upload = this.$refs.upload;
	/** 文件校验 */
	...
	let file = upload.uploadFiles[0];
	// 首次正常提交
	if(file.status == "ready") {
		this.loading.upload = true;
		upload.submit(); // 提交
	}
	// 再次提交的处理 fail success
	else {
		upload.clearFiles(); // 清空已上传的文件列表
        upload.handleStart(file.raw); // 手动格式化文件,这时文件状态已经置为 ready
        upload.submit(); // 重新提交
	}
}

如此,就大功告成!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值