需求
当上传的文件相对较大时,用户可能需要等待较长的时间,这个时候前端如果没有任何提示的话,体验不是很好,如果有上传进度提示,就会好很多。而要在上传过程实时显示上传进度,则需要已上传的大小和文件总大小。
前提
-
请求是异步的。因为要实时获取到上传的进度,则请求需是异步的,如果是同步的话,会直到请求完成才能获取到响应。
实现
这里总结的主要是js方面,至于进度条的显示,有的UI框架,比如semantic
就自带了进度条的实现,直接使用即可,没有的话也可以自己用改变div宽度等方式实现,这里不赘述。
如何获取到文件的上传进度?
Javascript的XMLHttpRequest
提供了一个progress
事件,这个事件会返回文件已上传的大小和总大小,根据这两个值,就可以计算上传进度了,关于这个方法,在《Javascript高级程序设计(第3版)》21章第3节中有叙述,有这本书在手的可以看一下。下面贴一下代码。
XMLHttpRequest:progress事件
使用Javascript的XMLHttpRequest的progress事件,实现示例代码为:
var formData = new FormData();
formData.append("file", document.getElementById('file').files[0]);
formData.append("token", token_value); // 其他参数按这样子加入
var xhr = new XMLHttpRequest();
xhr.open('POST', '/uploadurl');
// 上传完成后的回调函数
xhr.onload = function () {
if (xhr.status === 200) {
console.log('上传成功');
} else {
console.log('上传出错');
}
};
// 获取上传进度
xhr.upload.onprogress = function (event) {
if (event.lengthComputable) {
var percent = Math.floor(event.loaded / event.total * 100) ;
// 设置进度显示
$("#J_upload_progress").progress('set progress', percent);
}
};
xhr.send(formData);
复制代码
关于FormData和XMLHttpRequest
, 可以搜下W3C了解详情。
jQuery封装的xhr
jQuery
封装了xhr
的实现, 也可以使用jQuery
的ajax
获得上传进度,示例代码:
var formData = new FormData();
formData.append("file", document.getElementById('file').files[0]);
formData.append("token", token_value);
$.ajax({
url: "/uploadurl",
type: "POST",
data: formData,
processData: false, // 不要对data参数进行序列化处理,默认为true
contentType: false, // 不要设置Content-Type请求头,因为文件数据是以 multipart/form-data 来编码
xhr: function(){
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress',function(e) {
if (e.lengthComputable) {
var percent = Math.floor(e.loaded/e.total*100);
if(percent <= 100) {
$("#J_progress_bar").progress('set progress', percent);
$("#J_progress_label").html('已上传:'+percent+'%');
}
if(percent >= 100) {
$("#J_progress_label").html('文件上传完毕,请等待...');
$("#J_progress_label").addClass('success');
}
}
}, false);
}
return myXhr;
},
success: function(res){
// 请求成功
},
error: function(res) {
// 请求失败
console.log(res);
}
});
复制代码
关于jQuery ajax的xhr, 具体可查看W3C。
vue-resource
var formData = new FormData();
formData.append('token', token_value); // csrf token
formData.append("works", document.getElementById('file').files[0]); // file
var url = $("#R_batch_upload_url").val();
vm.$http.post(url, formData, {
progress: (e) => {
if (e.lengthComputable) {
var percent = Math.floor(e.loaded/e.total*100);
if(percent <= 100) {
$("#J_progress_bar").progress('set progress', percent);
$("#J_progress_label").html('已上传:'+percent+'%');
}
if(percent >= 100) {
$("#J_progress_label").html('文件上传完毕,提交表单中,请等待...');
$("#J_progress_label").addClass('success');
}
}
}
})
.then((res) => {
if(res.ok && res.status === 200) {
window.location.href = window.location.href;
}
}, (res) => {
if(res.status === 400) {
$("#J_progress_label").html('文件格式错误,请修改后重试');
$("#J_progress_label").addClass('warning');
console.log(res);
vm.errMsg.show = true;
vm.errMsg.msg = res.body.msg;
vm.canSend = true;
// TODO hide the loader dimmer
$("#J_upload_batch").dimmer("hide");
} else {
$("#J_progress_label").html(res.statusText);
$("#J_progress_label").addClass('warning');
}
});复制代码
七牛云储存
有些文件过大,后台会采取上传到七牛,再获取其地址保存到数据库的方式,这种方式的话,前端可以使用上面两种方式XMLHttpRequest或jQuery封装的xhr
实现发送请求及获取上传进度,如果需要更复杂的上传数据处理,也可以考虑使用七牛提供的配套Javascript SDK
实现,若是只需要进度提示的话,并不需要引入七牛JS SDK。
另外一点,上传成功后设置重定向到网站某页面的话,可能会报错跨域重定向。