用Vue&ElementUI Upload组件实现自定义顺序上传
产品要求:最多选择100个文件每张图最大2M需要给出每张图上传的结果:成功从列表中删除,失败提示网络错误,大于2m也需要提示支持重试遇到的问题:upload组件不支持多文件顺序上传,如果一次性上传100张图,压力有点大不支持顺序上传的原因,在elementui的源码中,手动调用submit方法时,会过滤status为ready的file,然后开始上传过程,上传过程异步,就会...
·
产品要求:
- 最多选择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>
更多推荐
已为社区贡献2条内容
所有评论(0)