在项目中碰到的多文件的拖拽上传总结。
html代码部分:
<body> <div class="fileBox"> <p class="fileInputP vm"> <i>选择文件</i> <!-- 选中单个文件上传 --> <input type="file" multiple id="fileInput" /> </p> <span id="fileSpan" class="vm">或者将文件拖到此处</span> <div class="mask"></div> </div> <!-- 文件信息列表 --> <table width="50%" border="1" class="fileList_parent"> <thead> <tr> <th>书名</th> <th>类型</th> <th>大小</th> <th>进度</th> <th>操作</th> </tr> </thead> <tbody class="fileList"> </tbody> </table> <input type="button" value="上传" id="fileBtn" /> </body>
.fileBox {
margin: 50px;
}
.fileInputP {
display: inline-block;
200px;
height: 30px;
border-radius: 5px;
overflow: hidden;
position: relative;
}
.fileInputP i {
display: inline-block;
200px;
height: 30px;
color: #fff;
background: #7d8f33;
text-align: center;
line-height: 30px;
}
#fileInput {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
opacity: 0;
}
#fileSpan {
display: inline-block;
300px;
height: 150px;
border: 2px dashed #ccc;
text-align: center;
line-height: 150px;
}
.fileList_parent {
margin: 50px;
display: none;
}
.fileList_parent th {
background: #dadada;
font-weight: bold;
}
.fileList_parent th,
.fileList_parent td {
padding: 5px;
}
.fileList tr:nth-of-type(2n) {
background: #dadada;
}
.progressParent {
200px;
height: 20px;
border-radius: 5px;
background: #ccc;
overflow: hidden;
position: relative;
}
.progress {
0%;
height: 20px;
background: #7d8f33;
}
.progressNum {
display: inline-block;
100%;
height: 20px;
text-align: center;
line-height: 20px;
color: #fff;
position: absolute;
left: 0;
top: 0;
}
#fileBtn {
margin-left: 50px;
display: none;
}
下面是关键的js代码部份
1 $(function() { 2 //元素 3 var oFileBox = $(".fileBox"); //选择文件父级盒子 4 var oFileInput = $("#fileInput"); //选择文件按钮 5 var oFileSpan = $("#fileSpan"); //选择文件框 6 var oFileList_parent = $(".fileList_parent"); //表格 7 var oFileList = $(".fileList"); //表格tbody 8 var oFileBtn = $("#fileBtn"); //上传按钮 9 10 var flieList = []; //数据,为一个复合数组 11 var sizeObj = []; //存放每个文件大小的数组,用来比较去重 12 13 //拖拽外部文件,进入目标元素触发 14 oFileSpan.on("dragenter", function() { 15 $(this).text("可以释放鼠标了!").css("background", "#ccc"); 16 }); 17 18 //拖拽外部文件,进入目标、离开目标之间,连续触发 19 oFileSpan.on("dragover", function() { 20 return false; 21 }); 22 23 //拖拽外部文件,离开目标元素触发 24 oFileSpan.on("dragleave", function() { 25 $(this).text("或者将文件拖到此处").css("background", "none"); 26 }); 27 28 //拖拽外部文件,在目标元素上释放鼠标触发 29 oFileSpan.on("drop", function(ev) { 30 var fs = ev.originalEvent.dataTransfer.files; 31 analysisList(fs); //解析列表函数 32 $(this).text("或者将文件拖到此处").css("background", "none"); 33 return false; 34 }); 35 36 //点击选择文件按钮选文件 37 oFileInput.on("change", function() { 38 analysisList(this.files); 39 }) 40 41 //解析列表函数 42 function analysisList(obj) { 43 //如果没有文件 44 if (obj.length < 1) { 45 return false; 46 } 47 48 for (var i = 0; i < obj.length; i++) { 49 50 var fileObj = obj[i]; //单个文件 51 var name = fileObj.name; //文件名 52 var size = fileObj.size; //文件大小 53 var type = fileType(name); //文件类型,获取的是文件的后缀 54 55 //文件大于30M,就不上传 56 if (size > 1024 * 1024 * 1024 || size == 0) { 57 alert('“' + name + '”超过了30M,不能上传'); 58 continue; 59 } 60 61 //文件类型不为这三种,就不上传 62 /*if( ("pdf/txt/epub").indexOf(type) == -1 ){ 63 alert('“'+ name +'”文件类型不对,不能上传'); 64 continue; 65 }*/ 66 67 //把文件大小放到一个数组中,然后再去比较,如果有比较上的,就认为重复了,不能上传 68 if (sizeObj.indexOf(size) != -1) { 69 alert('“' + name + '”已经选择,不能重复上传'); 70 continue; 71 } 72 73 //给json对象添加内容,得到选择的文件的数据 74 var itemArr = [fileObj, name, size, type]; //文件,文件名,文件大小,文件类型 75 flieList.push(itemArr); 76 77 //把这个文件的大小放进数组中 78 sizeObj.push(size); 79 } 80 createList() //生成列表 81 oFileList_parent.show(); //表格显示 82 oFileBtn.show(); //上传按钮显示 83 }; 84 85 86 //生成列表 87 function createList() { 88 oFileList.empty(); //先清空元素内容 89 for (var i = 0; i < flieList.length; i++) { 90 91 var fileData = flieList[i]; //flieList数组中的某一个 92 var objData = fileData[0]; //文件 93 var name = fileData[1]; //文件名 94 var size = fileData[2]; //文件大小 95 var type = fileData[3]; //文件类型 96 var volume = bytesToSize(size); //文件大小格式化 97 98 99 var oTr = $("<tr></tr>"); 100 var str = '<td><cite title="' + name + '">' + name + '</cite></td>'; 101 str += '<td>' + type + '</td>'; 102 str += '<td>' + volume + '</td>'; 103 str += '<td>'; 104 str += '<div class="progressParent">'; 105 str += '<p class="progress"></p>'; 106 str += '<span class="progressNum">0%</span>'; 107 str += '</div>'; 108 str += '</td>'; 109 str += '<td><a href="javascript:;" class="operation">删除</a></td>'; 110 111 oTr.html(str); 112 oTr.appendTo(oFileList); 113 } 114 } 115 116 //删除表格行 117 oFileList.on("click", "a.operation", function() { 118 var oTr = $(this).parents("tr"); 119 var index = oTr.index(); 120 oTr.remove(); //删除这一行 121 flieList.splice(index, 1); //删除数据 122 sizeObj.splice(index, 1); //删除文件大小数组中的项 123 124 //console.log(flieList); 125 //console.log(sizeObj); 126 127 }); 128 129 130 //上传 131 oFileBtn.on("click", function() { 132 oFileBtn.off(); 133 var tr = oFileList.find("tr"); //获取所有tr列表 134 var successNum = 0; //已上传成功的数目 135 oFileList.off(); //取消删除事件 136 oFileBox.slideUp(); //隐藏输入框 137 oFileList.find("a.operation").text("等待上传"); 138 139 140 for (var i = 0; i < tr.length; i++) { 141 uploadFn(tr.eq(i), i); //参数为当前项,下标 142 } 143 144 function uploadFn(obj, i) { 145 146 var formData = new FormData(); 147 var arrNow = flieList[i]; //获取数据数组的当前项 148 149 // 从当前项中获取上传文件,放到 formData对象里面,formData参数以key name的方式 150 var result = arrNow[0]; //数据 151 formData.append("imageFile", result); // 给后台传的参数 152 153 var name = arrNow[1]; //文件名 154 formData.append("email", name); // 给后台传的参数 155 156 var progress = obj.find(".progress"); //上传进度背景元素 157 var progressNum = obj.find(".progressNum"); //上传进度元素文字 158 var oOperation = obj.find("a.operation"); //按钮 159 160 oOperation.text("正在上传"); //改变操作按钮 161 oOperation.off(); 162 163 var request = $.ajax({ 164 type: "POST", 165 url: "// 上传文件的路径", 166 data: formData, //这里上传的数据使用了formData 对象 167 processData: false, //必须false才会自动加上正确的Content-Type 168 contentType: false, 169 170 //这里我们先拿到jQuery产生的XMLHttpRequest对象,为其增加 progress 事件绑定,然后再返回交给ajax使用 171 xhr: function() { 172 var xhr = $.ajaxSettings.xhr(); 173 if (onprogress && xhr.upload) { 174 xhr.upload.addEventListener("progress", onprogress, false); 175 return xhr; 176 } 177 }, 178 179 //上传成功后回调 180 success: function() { 181 oOperation.text("成功"); 182 successNum++; 183 console.log(successNum); 184 if (successNum == tr.length) { 185 open("http://www.baidu.com", "_self"); //如果全部传成功了,跳转 186 } 187 }, 188 189 //上传失败后回调 190 error: function() { 191 oOperation.text("重传"); 192 oOperation.on("click", function() { 193 request.abort(); //终止本次 194 uploadFn(obj, i); 195 }); 196 } 197 198 }); 199 200 201 //侦查附件上传情况 ,这个方法大概0.05-0.1秒执行一次 202 function onprogress(evt) { 203 var loaded = evt.loaded; //已经上传大小情况 204 var tot = evt.total; //附件总大小 205 var per = Math.floor(100 * loaded / tot); //已经上传的百分比 206 progressNum.html(per + "%"); 207 progress.css("width", per + "%"); 208 } 209 } 210 }); 211 }) 212 213 //字节大小转换,参数为b 214 function bytesToSize(bytes) { 215 var sizes = ['Bytes', 'KB', 'MB']; 216 if (bytes == 0) return 'n/a'; 217 var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); 218 return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]; 219 }; 220 221 //通过文件名,返回文件的后缀名 222 function fileType(name) { 223 var nameArr = name.split("."); 224 return nameArr[nameArr.length - 1].toLowerCase(); 225 }
完成后效果如下图所示: