最近在做项目时,遇到一个需求是,上传文件过程中需要判断下是否已经存在该文件,如果存在,让用户来决定是否继续上传,这里边有两个注意点:
- 是否存在该文件,需要调取后台接口返回结果来,涉及一个异步问题;
- 是否继续上传,需要在上传回调函数中通过return false来阻止文件继续上传。
首先我的思路是在before回调中做中断,我采用的layui版本是v2.5.6,在更低的版本中需要改下upload.js源码,y=function(){return "choose" === i ? l.choose && l.choose(g) : ((l.before && l.before(g)) === false ? '' : o.ie ? o.ie > 9 ? u() : c() : void u()) };
然后在页面中按部就班写下upload相关业务代码:
upload.render({
elem: '#chooseBtn',
url: 'XXXXX',
accept: 'file',
exts: 'xls|excel|xlsx',
headers: {
token: localStorage.getItem('token')
},
data: {},
before: function(obj) {
var flag = true;
layer.load(); //上传loading
files = obj.pushFile();
this.data = {
institution: $("#dropdownMenu1").val(),
handle_class: $("#handle_class").val(),
file_name: files[fileId].name
}
obj.preview(function (index, file, result) {
file_name = file.name
fileId = index;
$("#fileWrap").append('<li id="' + fileId + '"><span>' + file.name +
'上传中</span><i class="layui-icon layui-icon-close"></i></li>'
)
$.ajax({
url: 'mon/monitor/clean/checkUpload.json',
contentType: 'application/x-www-form-urlencoded',
type: 'post',
beforeSend: function (request) {
request.setRequestHeader('token', localStorage.getItem('token'));
},
data: {
institution: $("#dropdownMenu1").val(),
file_name: file.name
},
dataType: "json", //服务器返回数据的类型为json
success: function (data) {
if (data.code == '100') {
$('#chooseBtn').css('display', 'none')
flag = true
} else {
if (data.code == '104') {
layer.confirm(data.msg + ',点击确定将替换原文件', {
title: '提示',
btn: ['取消', '确定']
},
function (index) {
//do something
delete files[fileId];
$("#fileWrap").find('li[id="' + fileId + '"]').remove();
layer.close(index);
flag = false
return false
},
function (index) {
flag = true
obj.upload(fileId, file)
$('#chooseBtn').css('display', 'none')
});
return false
} else {
flag = false
layer.msg(data.msg)
}
}
},
error: function (data) {
flag = false
console.error(data)
}
})
});
return flag
},
done: function (res, index, upload) {
console.log(res, index)
layer.closeAll('loading'); //关闭loading
},
error: function (index, upload) {
layer.closeAll('loading'); //关闭loading
delete files[index];
$("#fileWrap").find('li[id="' + index + '"]').remove();
$("#chooseBtn").css('display', 'inline-block')
}
});
这样做看似没有问题,但是实际上选完文件之后就立即上传了,而去重判断的接口甚至是文件已经上传成功了才返回了结果,在上传文件前的flag读取的其实还是初始值true,因此并没有阻止上传进程,后来又尝试将去重改为同步async:false,又将去重整个赋值给一个函数,最后在before中return这个函数,结果就是flag虽然变成了期望的值false,但是依然没有阻止上传进程...
多次尝试之后,灵机一动既然立即上传不行,那可以试试触发按钮上传,这样做的好处是,选择文件其实只执行了choose这个选择文件回调,当点击了设置的这个上传开关按钮之后才会执行before,done,error这些回调,因此最终的解决思路就是:
- 选择文件后立马做(choose回调中)去重判断,并保存判断的结果;
- 点击上传按钮后立马决定(拿着去重结果)是否继续上传
代码仅供参考
var files = null;
var fileId = '';
var file_name = '';
var flag = true;
var uploadInst = upload.render({
elem: '#chooseBtn',
url: 'XXX',
accept: 'file',
auto: false,
bindAction: '#startBtn',
exts: 'xls|excel|xlsx',
headers: {
token: localStorage.getItem('token')
},
data: {},
xhr: xhrOnProgress, //传入监听函数!important
choose: function(obj) {
$("#startBtn").css('display', 'inline-block')
files = obj.pushFile();
obj.preview(function (index, file, result) {
file_name = file.name
fileId = index;
$("#fileWrap").append('<li id="' + fileId + '"><span>' + file.name +'上传中</span><i class="layui-icon layui-icon-close"></i><div class="layui-progress layui-progress-big" lay-filter="progressBar'+fileId+'" lay-showPercent="yes"><div class="layui-progress-bar layui-bg-red" lay-percent="0%"></div></div></li>')
element.render('progress', 'progressBar'+fileId);
$.ajax({
url: 'xxx',
contentType: 'application/x-www-form-urlencoded',
type: 'post',
async: false,
beforeSend: function (request) {
request.setRequestHeader('token', localStorage.getItem('token'));
},
data: {
institution: $("#dropdownMenu1").val(),
file_name: file.name
},
dataType: "json",
success: function (data) {
if (data.code == '100') {
$('#chooseBtn').css('display', 'none')
flag = true
} else {
if (data.code == '104') {
layer.confirm(data.msg + ',点击确定将替换原文件', {
title: '提示',
btn: ['取消', '确定']
},
function (index) {
//do something
delete files[fileId];
$("#fileWrap").find('li[id="' + fileId + '"]').remove();
layer.close(index);
flag = false
return false
},
function (index) {
flag = true
obj.upload(fileId, file)
$('#chooseBtn').css('display', 'none')
});
return false
} else {
flag = false
layer.msg(data.msg)
}
}
},
error: function (data) {
flag = false
console.error(data)
}
})
});
},
before: function (obj) {
layer.load(); //上传loading
console.log('this:', this)
this.data = {
institution: $("#dropdownMenu1").val(),
handle_class: $("#handle_class").val(),
file_name: files[fileId].name
}
return flag
},
progress: function(n, elem){
var percent = n + '%' //获取进度百分比
element.progress('progressBar'+fileId, percent); //可配合 layui 进度条元素使用
},
done: function (res, index, upload) {
console.log(res, index)
layer.closeAll('loading'); //关闭loading
if (files) {
delete files[index];
}
if (res.code == '100') {
fileSuccess = true
$("#fileWrap li span")[0].innerText = file_name
} else {
layer.msg(res.msg)
$("#fileWrap").find('li[id="' + fileId + '"]').remove();
fileSuccess = false
}
$("#startBtn").css('display', 'none');
$('#chooseBtn').css('display', 'inline-block');
},
error: function (index, upload) {
layer.closeAll('loading'); //关闭loading
delete files[index];
$("#fileWrap").find('li[id="' + index + '"]').remove();
$("#chooseBtn").css('display', 'inline-block')
}
});
$("#fileWrap").on('click', 'li i', function(e) {
var fileId = $(this).parent('li').attr("id");
delete files[fileId];
$(this).parent('li').remove();
$("#chooseBtn").css('display', 'inline-block')
});
页面如图:
点击上传开关后,点击确定之后还需才会上传,否则重新选择文件,再次触发choose回调,进行去重判断...
上传成功后隐藏了上传开关
再多一点废话:进度条
同样是在upload.js文件中需要在p.prototype.config中加上xhr,即p.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1,xhr: function() {}}
然后创建进度条监听函数
var xhrOnProgress = function (fun) {
xhrOnProgress.onprogress = fun; //绑定监听
//使用闭包实现监听绑
return function () {
//通过$.ajaxSettings.xhr();获得XMLHttpRequest对象
var xhr = $.ajaxSettings.xhr();
//判断监听函数是否为函数
if (typeof xhrOnProgress.onprogress !== 'function')
return xhr;
//如果有监听函数并且xhr对象支持绑定时就把监听函数绑定上去
if (xhrOnProgress.onprogress && xhr.upload) {
xhr.upload.onprogress = xhrOnProgress.onprogress;
}
return xhr;
}
}
进度条在选择文件的预览方法已经追加了dom,但是在此必须激活一下,否则会出现的情况是进度条虽然动态变化了,但是上面的文字也就是百分数没有跟着变,因此需这行:element.render('progress', 'progressBar'+fileId);
然后在progress回调中更新进度就好了
今天就分享这么多吧,有更好的方案一起讨论哟~~~