描述
本文所描述的上传文件主要是应用于手机端,PC端可以酌情改造。
应用场景:
手机浏览器一次上传多张图片或者文件,将文件每5个拆分为一组上传。上传进度条为手机端上传至后台所用时间不包含后台耗时。
选择图片用H5的input file标签(能否选多张看浏览器了),上传功能使用XMLHttpRequest后面简称xhr,jquery和zepto中都包含。
html
<span style="font-size:14px;"><div id="uploadBtn" class="needsclick"><span class="needsclick">上传照片</span></div>
<input type="file" id="uploadFile" name="uploadFile" multiple="multiple" accept="image/*" style="display: none"/></span>
1.将uploadBtn的点击事件绑定到file的点击事件上(这部分不多说),监听file的onchange事件获取上传的文件。↑
<span style="font-size:14px;"> var batchCount = 1;
var batchNum = 5;
var loadArr = [];
$(function() {
/**
* file的onchange事件,处理上传完成后的数据
*/
$('#uploadFile').on('change', function(){
var files = $('#uploadFile').prop('files');
var allFileCount = files.length;
if(files.length == 0){
return;
}
var fd;
// 计算一共会分成几个批次
batchCount = Math.ceil(allFileCount/batchNum);
for(var i = 0;i < allFileCount; i++){
if(i%batchNum == 0){
fd = new FormData();
}
if((i+1)%batchNum == 0 || (i+1) == allFileCount){
//监听事件
var xhr = new XMLHttpRequest();
if((i+1) == allFileCount){
var funNum = batchCount -1;
}else{
var funNum = (i- (batchNum -1))/batchNum;
}
<span style="color:#CC0000;">var c = "printFunName"+funNum; //根据不同的名字区分属于哪个批次(不能纯数字),否则批次会乱
eval("function "+c+"(evt){uploadProgress(evt);}");
xhr.upload.onprogress = eval(c);//绑定进度条事件</span>
xhr.onload = function(evt){ // 加载完成事件,包含502等结果需要判断状态
loadSuccess(evt);
};
xhr.onerror = function(){ // 加载error事件
loadError(evt);
}
//发送文件和表单自定义参数
xhr.open("POST", "/photo/uploadFile",true);// 设置请求地址,true表示异步,反之...
xhr.send(fd); // 发送请求
}
}
});</span>
2.绑定各种事件,进度条最关键需要讲各个进程的进度累加 ↑
<span style="font-size:14px;"> /**
* 加载进度方法
* @param evt
*/
var progressArr = [];
function uploadProgress(evt){
if (evt.lengthComputable) {// 判断是否有进度
<span style="color:#FF0000;">var funName = evt.currentTarget.onprogress.name; // 实在是没发传参了,只好用这个了,有好的方法可以留言
var funIndex = funName.substr(12);// 截取方法名的字符串后的数字,用来判断是哪个批次的
//evt.loaded:文件上传的大小 evt.total:文件总的大小
var percentComplete = Math.round((evt.loaded / evt.total) * 100);
progressArr[funIndex] = percentComplete; // 把当前进度放进一个数组里
var prpgressTotal = 0;
for(var i = 0; i < progressArr.length; i++){ // 遍历数组所有的进度,相加
if(progressArr[i] != "" || progressArr[i] != undefined || progressArr[i] != 0){
prpgressTotal = prpgressTotal + progressArr[i];//一次上传图片分了4批这里相加的结果在0--400之间
}
}
//加载进度条,同时显示信息,这个位置要除以批次数量,假如最大400除以4个批次就是100%,四舍五入小数点
var str = '' + Math.round(prpgressTotal / batchCount) + '%';
// str就是一个百分比的字符串,自己展示出来即可
}
}</span>
4.进度条这是最大的难点,因为是异步的结果需要保证每个批次的进度不要乱,放到数组中这样每个批次只会有一个最大的进度数字。用方法名称开传递参数实属无奈,因为这里拿不到response。 ↑
<span style="color:#000000;"> /**
* 上传文件成功事件
*/
function loadSuccess(evt){
var loadNum; //积累批次
if(evt.target.status == 200){ // 200成功
var jsonData = JSON.parse(evt.target.response);
loadNum = loadArr.push(jsonData);// 每次把response的数据保留,所有批次都到了一起处理,可以单独显示结果
// 其中出现错误的请求要记录,要不后面不知道一种成功了几张,一个error表示一个批次都错误
loadNum = loadArr.push("error");
}
if(loadNum == batchCount){ // 批次数等于完成的总数时就是所有数据都有结果了
buildMessage(); // 自行处理loadArr中的结果,全局变量
}
}
5.处理返回结果主要是把error的问题处理好的就可以了,失败的监听事件跟成功的同理,不写了 ↑总结
分批上传可以避免图片太多一次请求失败全失败的结果,而且速度也有提升,希望对大家有帮助。写的不对的地方请指正