昨天研究了一天文件上传进度条的实现,折腾了一天终于是完成了,期间遇到了各种BUG,让人不禁泪落。
这里,我们将使用最少量的AJAX来实现这个功能,没有任何对浏览器支持性的检测,这样更容易明白。还有一点需要说明的是,后台也是应该来掺和一脚(配合)的,当然,非常简单,只要确认接受这个文件就行(后面将说明)。我使用的是Django框架来做的后台。
没什么好多说的,先上代码,代码中会给出详细的解释。先给出前端的:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script>
function on_progress(evt) { //看这个函数之前先看upload函数。这个函数可以接收一个evt(event)对象(细节自行查询progress),他有3个属性lengthComputable,loaded,total,第一个属性是个bool类型的,代表是否支持,第二个代表当前上传的大小,第三个为总的大小,由此便可以计算出实时上传的百分比
if(evt.lengthComputable) {
var ele = document.getElementById('2');
var percent = Math.round((evt.loaded) * 100 / evt.total);
ele.style.width = percent + '%';
document.getElementById('3').innerHTML = percent + '%';
}
}
function upload() {
var xhr = new XMLHttpRequest();
var file = document.getElementById('file').files[0]; //取得文件数据,而.file对象只是文件信息
var form = new FormData(); //FormData是HTML5为实现序列化表单而提供的类,更多细节可自行查询
form.append('file',file); //这里为序列化表单对象form添加一个元素,即file
xhr.upload.addEventListener('progress',on_progress,false); //xhr对象含有一个upload对象,它有一个progress事件,在文件上传过程中会被不断触发,我们为这个事件对应一个处理函数,每当事件触发就会调用这个函数,于是便可利用这个函数来修改当前进度,更多细节可自行查询
xhr.open('POST','http://127.0.0.1:8000/upload/',true); //请将url改成上传url
xhr.setRequestHeader('X-CSRFTOKEN','{{ request.COOKIES.csrftoken }}'); //此处为Django要求,可无视,或者换成相应后台所要求的CSRF防护,不是django用户请去掉
xhr.send(form); //发送表单
}
</script>
</head>
<body>
<form>
{% csrf_token %} //Django要求,不是Django用户请去除
<div id='1' style="height:20px;width:100px;border:2px solid gray;float:left;margin-right:10px;">
<div id='2' style="height:100%;width:0px;background:gray;"></div>
</div>
<b style="margin-right:20px" id='3'>0%</b>
<input type="file" id='file' class='file' name="file"><br><br>
<button type="button" οnclick="upload();">上传</button>
</form>
</body>
</html>
好了,前端的事情已经干完了,接下来就是确保后台不会拒绝,也就是确认接受这个文件,当然还有一点便是上传界面也要由后台来提供,否则会出现跨域提交失败。在Django中大概就是下面这样:
urls.py有下面2个模式匹配
url(r'^upload_page/$', upload_page)
url(r'^upload/$', upload)
views.py有下面2个请求处理函数
def upload_page(request):
return render(request,'upload_page.html') #这里upload_page便是上面的前端html文件
def upload(request):
file = request.FILES #一定要调用上传的文件(不管你干嘛,保存也好,啥也不干也好,反正不调用就出错了,估计是默认不调用就不接收吧。。)才能用ajax上传成功,否则报错,原因不明
return HttpResponse()