用Vue&ElementUI Upload组件实现自定义顺序上传

产品要求:

  • 最多选择100个文件
  • 每张图最大2M
  • 需要给出每张图上传的结果:成功从列表中删除,失败提示网络错误,大于2m也需要提示
  • 支持重试

遇到的问题:

  • upload组件不支持多文件顺序上传,如果一次性上传100张图,压力有点大

不支持顺序上传的原因,在elementui的源码中,手动调用submit方法时,会过滤status为ready的file,然后开始上传过程,上传过程异步,就会同时上传所有ready状态文件。

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

既然知道了submit方法会过滤ready状态的文件,我们可以手工控制file的状态,然后自己反复调用submit方法。

先看一下完成图:

代码:

<template>
	<div>
		<el-dialog :title="isUploading ? '导入中' : '导入数据'" :visible.sync="dialogVisible"  @close="clear" :center="true" :lock-scroll="true" custom-class="import-data-dlg" width="1300px">
			<div class="tip" v-if="!isUploading">每张不超过2M,格式为jpg/png</div>
			<div v-else class="upload-progress">
				<el-progress :show-text="false" :stroke-width="14" :percentage="percentage" color="rgba(19,206,102,1)" ></el-progress><span class="tip">{{uploadingTotal - fileListCache.length}}/{{uploadingTotal}}</span>
			</div>
			<div class="images">
				<el-upload
					:class="{'has-files': hasSelectedFiles, 'upload-images': true}"
					action=""
					ref="uploader"
					:auto-upload="false"
					:on-change="handleChange"
					:on-remove="handleRemove"
					multiple
					:limit="100"
					accept=".png,.jpg,.jpeg"
					:http-request="uploadImages"
					list-type="picture-card">
					<i class="el-icon-plus"></i>
				</el-upload>
			</div>
			<div class="tip bottom" v-if="hasSelectedFiles">已选择<span>{{total}}</span>张图片</div>
			<div slot="footer" class="dialog-footer pull-right" v-if="hasSelectedFiles">
				<el-button @click="cancel">放弃</el-button>
				<el-button type="primary" @click="ok">开始导入</el-button>
			</div>
		</el-dialog>
	</div>
</template>

<script>
import _ from 'lodash';
import $ from 'jquery';
import {mapState} from 'vuex';
import {CommonSrv, Deferred} from 'datapp';
import {Constants} from 'utils';

export default {
	name: 'ImportDataDlg',
	components: {
	},
	computed: {
		...mapState([
			'loginUser'
		]),
		hasSelectedFiles () {
			return this.fileListCache && this.fileListCache.length;
		}
	},
	data: function () {
		
		return {
			isUploading: false,
			fileListCache: [],
			imageUrls: [],
			total: 0,
			uploadingTotal: 0,
			percentage: 0,
			uploadingIdx: 0,
			dialogVisible: false,
			deferred: ''
		};
	},
	methods: {
		show (data = {}) {

			this.dialogVisible = true;

			this.deferred = new Deferred();
			return this.deferred;
		},
		
		handleChange (file, fileList) {
			this.fileListCache = fileList;
		},

		handleRemove (file, fileList) {
			this.total--;
			this.handleChange(file, fileList);
		},

		uploadImages (param) {
			console.log('uploading.... param...', param.file.name);

		    this.uploadingIdx++;
			window.setTimeout((i) => {

			    if (i % 3 === 0) {
			 		param.onSuccess();
			 		this.uploadSuccess(param.file);
			 	} else if (i % 3 === 1) {
			 		this.uploadError(param.file);
			 	} else {
			 		this.uploadBigger(param.file);
			 	}
			 	this.upload();
			}, 1500, this.uploadingIdx);
		},

		upload () {
			let idx = _.findIndex(this.fileListCache, f => f.status === 'waiting');
			console.log('idx....', idx);
			if (idx !== -1) {
				this.fileListCache[idx].status = 'ready';
				this.$refs.uploader.submit();
			} else {
				this.isUploading = false;

				console.error('need call api');
			}
		},

		uploadSuccess (file) {
			console.log('success....', file.status, file.name);
			_.remove(this.fileListCache, f => f.name === file.name);
			this.total--;
			this.percentage = ((this.uploadingTotal - this.fileListCache.length) / this.uploadingTotal) * 100;
		},

		uploadError (file) {
			console.log('error....', file.status, file.name);
			this.$refs.uploader.getFile(file).status = 'error';
		},

		uploadBigger (file) {
			console.log('bigger....', file.status, file.name);
			this.$refs.uploader.getFile(file).status = 'bigger';
		},

		ok () {
			if (this.fileListCache.length) {
				let waitingFiles = this.fileListCache.filter(f => f.status !== 'bigger');
				if (waitingFiles.length) {
					waitingFiles.forEach(f => { f.status = 'waiting'; });

					this.uploadingTotal = this.fileListCache.length;
					this.percentage = 0;
					this.isUploading = true;
				}

				this.upload();
			}
			// this.dialogVisible = false;
		},

		cancel () {
			this.dialogVisible = false;
		},
		clear () {
			this.isUploading = false;
			this.total = 0;
			this.fileListCache.length = 0;
			this.imageUrls = [];
		}
	},
	mounted () {
		$('.import-data-dlg').on('change', '.el-upload__input', (evt) => {
			this.total += evt.target.files.length;
		});
	}
};
</script>
<style lang="scss">
	.import-data-dlg {
		height: 720px;

		.el-dialog__body {
			padding-top: 0;
			padding-bottom: 0;

			.tip {
				font-size: 13px;
				color: #99a9bf;
				text-align: center;

				span {
					color: #000;
				}

				&.bottom {
					margin-top: 20px;
					text-align: left;
				}
			}

			.upload-progress {
				text-align: center;

				.el-progress {
					width: 180px;
					display: inline-block;
					margin: auto;
				}

				.el-progress-bar__outer {
					border-radius: 0;

					.el-progress-bar__inner {
						border-radius: 0;
					}
				}

				.tip {
					font-size: 12px;
					color: #475669;
					margin-left: 5px;
					vertical-align: text-bottom;
				}
			}

			.images {
				overflow-y: auto;
				margin-top: 34px;
				height: 520px;
				width: 100%;
				margin: auto;
			}

			.upload-images {
				text-align: center;
				padding-top: 150px;

				&.has-files {
					padding-top: 35px;
				}

				.el-upload-list--picture-card .el-upload-list__item {
					width: 120px;
					height: 120px;
					margin: 0 20px 20px 0;
					border-radius: 0;

					img {
						object-fit: cover;
					}

					&::after {
						position: absolute;
						display: inline-block;
						bottom: 0;
						left: 0;
						right: 0;
						height: 35px;
						line-height: 35px;
						color: white;
						font-size: 13px;
						background: rgba(0, 0, 0, .5);
					}

					&.is-error::after {
						content: '网络错误';
					}

					&.is-bigger::after {
						content: '大于2M';
					}
				}

				.el-upload-list--picture-card {
					.el-progress {
						width: 100px;

						.el-progress-circle {
							width: 100px !important;
							height: 100px !important;
						}
					}
				}

				.el-upload--picture-card {
					width: 120px;
					height: 120px;
					line-height: 118px;
					border-radius: 0;
				}
			}
		}
	}
</style>

猜你喜欢

转载自blog.csdn.net/kittyjie/article/details/85775114