前言:
之前写过一个文件上传的模块,但是是多个input上传的,而且使用的是jQuery.form打包上传的,这样子就觉得还是有点不太方便。
1.提交的时候需要将整个form提交上去,换句话说就是需要将要提交的内容使用form将内容包括起来
2. 文件input虽然可以在页面上设置增减功能的办法调整文件数量,但是一般会设置上限(例如最多添加10个input,不然太多了页面就太乱了,当然这个情况在大部分情况下不是什么大问题,只有在要上传大量零散文件的时候才算有问题)
——————————————————————下面是我改进的方法———————————————————————
html:
<div class="input-group">
<input type="file" id="attachment" multiple>
<span id="progress_bar" style="color: #1AB394;display: table-cell">span>
div>
<ul id="attachment_list">ul>
<button class="btn btn-file">upload filebutton>
html中,只有input是主要的,其他的元素都可以按照需要替换掉。
js:
$.ajaxSetup({ //laravel中的request要带这个header参数
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('.btn-file').click(function(){
if($('#attachment').val() == '')
alert('请选择文件再上传');
else{
var path = $('#attachment')[0].files;
var formData = new FormData();
var names = '';
/*
提示:FormData不能写数组,array json都不行,能写简单的key->value键值对。
键值对中key不能是中文,不然后台读不出来,而且要保证key的唯一性,
那么我就用文件名path[i].name用md5加密一下好了,当然你也可以用自己喜欢的加密方式。
因为laravel不能便利地读取所有file,只能用file('key')读取key值的value,
是的,所以你不知道key值是读不出你要的东西的。因为文件的key是变化的,所以我这里写定一个info字段,
然后把文件的key写成字符串,然后后台解析字符串,再根据里面的字段获取文件。
你也可以写其他需要的数据的键值对到FormData里面,一并传到后台,当成一个虚拟form表单用就行了。
/*
for(var i= 0,name;i',';
}
formData.append('info',names);
$.ajax({
url: "{{route('upload')}}",
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false,
beforeSend: function(){
$('#progress_bar').css('color','#1AB394').show();
},
success: function(result
{
$('#progress_bar').html(result.info).css('color','black').fadeOut(3000,function(){$(this).html('')});
},
error: function (result) {
},
xhr: function(){
var xhr = $.ajaxSettings.xhr();
if(onprogress && xhr.upload) {
xhr.upload.addEventListener("progress" , onprogress, false);
return xhr;
}
}
});
/*
小tips:在网上查找遇到一些方法(例如function A()),没有详细介绍,不知道总共完整传多少个参数,
每个参数长什么样子的,可以写成function A(a,b,c,d,e,…………){//然后写log打印出来},
这里只有一个event对象参数,所以我写4个形参上去,然后写日志出来,只有第一个参数写出来是一个对象,
而且里面有什么属性也会写出来,后面3个形参则输出为空,
那么这时候就能写定 function A(obj){//只有一个参数,自己写个喜欢的形参名}。
前端后台都能用这个小技巧哦~
*/
function onprogress(evt){
console.log(evt);
var loaded = evt.loaded;
var tot = evt.total;
$('#progress_bar').html(Math.floor(100*loaded/tot)+'%');
}
这里的js是用一个FormData对象,将数据填充进去,然后伪装成从form里提取的数据(意思大概是这个意思吧~),如果要上传文件,那么和普通的ajax传数据的参数有些不同,可以按照我上面写的设置参数,ajax具体参数有什么作用可以看我这个blog:http://blog.csdn.net/qq_29238009/article/details/77506048。
因为原生ajax是有进度的参数的,progress还是什么来着,但是jQuery是封装了原生ajax对象的一种对象,是没有设置这个参数的,所以不能像success、error这样直接写函数。但是jQuery有个参数xhr能够返回原生ajax对象,然后通过原生ajax对象进行进度条的操作,如上ajax写好xhr以及它所调用的onprogress函数,就能获取ajax上传的数据进度了。
写好前后台后上传大概就是这个效果了。
input的文件改变的时候写一下ul列表,然后上传的时候写一下进度百分比。当然这些都是可以按需调整的,我这里简单写写,可以设计一下写的更漂亮丰富,加多点特效,写成进度条之类的,也可以删减不要
后台我写过一个blog,因为前端是js,但是后台可以是不同语言,我这里用的后台是laravel框架,用php写的,如果你是用其他语言写的后台,可以自己写过一个后台适配这个前端。反正就是ajax传一些文件和字段到后台而已,接收好就行了,该怎么处理看自己的业务逻辑需要怎么做吧。
————————————————————————————————————————
laravel后端篇的blog:http://blog.csdn.net/qq_29238009/article/details/77651289
已知缺陷:
1. 和我前言说的那种N个文件用N个input相比,这样的多选上传只能选中同一级目录下的文件(当然这个也是能解决的,因为FormData能模拟表单,所以你可以在页面上随意不同位置写上input然后填充进FormData里面,同样不用form标签包裹住,也能显示上传进度。总的来说,要上传N个级目录下的文件,就要有N个input,同一级目录上传文件就一个input可以了)