HTML5 拖拽上传
写了个拖拽上传的效果。
说明:默认情况下的事件对象是body,就是可以直接将图片拖到浏览器窗口上,事件对象也可以是其它HTML元素,只需将该元素的ID赋给target就行了,另外
也可以是文件域(将下面的HTML代码里的注释去掉就可以查看效果)
效果图:
HTML:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8" /> 5 <link rel="stylesheet" type="text/css" media="all" href="ajaxFileUpload2.css"/> 6 </head> 7 <body> 8 <!--<input type="file" id="fielUpload" name="fielUpload" multiple/>--> 9 <div style="height:2000px;"></div> 10 <script src="ajaxFileUpload2.js"></script> 11 <script> 12 ajaxUpload({ 13 //默认情况下的事件对象是body,直接将图片拖到浏览器中就可以了 14 //也可以设置事件对象为HTML元素,target为元素ID就行了 15 //也可以是文件域 16 //target:'fielUpload', 17 url:'result3.php', 18 thumbWidth:220, 19 thumbHeight:138, 20 success:function(xhr){ 21 var data = xhr.responseText; 22 console.log(decodeURIComponent(data)); 23 }, 24 callback:function(){ 25 console.log('done!') 26 } 27 }); 28 </script> 29 </body> 30 </html>
JS:
1 /** 2 * @author Administrator 3 */ 4 (function(win){ 5 var doc = win.document,db = doc.body,oFiles=[]; 6 var isOpera=/opera(\/| )(\d+(\.\d+)?)(.+?(version\/(\d+(\.\d+)?)))?/i.test(navigator.userAgent) ? ( RegExp["\x246"] || RegExp["\x242"] ) : false; 7 var ajaxUpload = function(opts){return new ajaxUpload.prototype.init(opts);}; 8 ajaxUpload.prototype = { 9 constructor:ajaxUpload, 10 init:function(opts){ 11 var set = extend({ 12 target:'body', 13 boxWidth:950, 14 boxHeight:500, 15 thumbWidth:200, 16 thumbHeight:200, 17 url:'', 18 callback:function(){} 19 },opts||{}); 20 var target = set.target === 'body' ? db : $(set.target); 21 if(target.type == 'file'){ 22 target.addEventListener('change',handleChange(set),false); 23 }else{ 24 target.addEventListener('dragenter',function(e){ e.preventDefault();},false); 25 target.addEventListener('dragover',function(e){ e.preventDefault();},false); 26 target.addEventListener('drop',function(e){e.preventDefault();handleDrop(e,set);},false); 27 }; 28 } 29 }; 30 ajaxUpload.prototype.init.prototype = ajaxUpload.prototype; 31 win.ajaxUpload = ajaxUpload; 32 /**********************************************************************************/ 33 function handleChange(set){ 34 return function(){ 35 handleFiles(this.files,set); 36 }; 37 }; 38 function handleDrop(e,set){ 39 handleFiles(e.dataTransfer.files,set); 40 }; 41 function handleFiles(files,set){ 42 var fragment = createContent(files); 43 //如果已经有文件了,则只需要追加就可以了 44 if(!handleFiles.box || !handleFiles.ul){ 45 handleFiles.box = createWindow(set); 46 handleFiles.ul = createEl('<ul id="imgList"></ul>'); 47 handleFiles.box.content.appendChild(handleFiles.ul); 48 db.addEventListener('click',handleControl,false); 49 handleFiles.box.btnUpload.addEventListener('click',handleUpload(set),false); 50 handleFiles.box.btnCancel.addEventListener('click',handleCancel,false); 51 handleFiles.box.close.addEventListener('click',handleClose,false); 52 } 53 handleFiles.ul.appendChild(fragment); 54 }; 55 function createContent(files){ 56 var item,imgBox,img,reader,editRemark,file,fragment = doc.createDocumentFragment(); 57 oFiles = merge(oFiles,files); 58 each(files,function(i){ 59 file = this; 60 if(!(/image\/.*/.test(file.type))) return; 61 item = createEl('<li class="sbi_item"><p class="remark"></p><span class="progressbox"><em class="progress"></em></span><span class="control"><a class="edit" href="javascript:void(0)">备注</a><a class="del" href="javascript:void(0)">删除</a></span></li>',fragment); 62 editRemark = createEl('<textarea class="editRemark"></textarea>',item); 63 imgBox = createEl('<span class="img_preview"></span>',item); 64 img = createEl('<img src="" index="'+i+'" rel=""/>',imgBox); 65 //window.URL.createObjectURL(file)在opera中返回的竟然是[object file],很蛋疼 66 if(window.URL && !isOpera){ 67 img.src = window.URL.createObjectURL(file); 68 window.URL.revokeObjectURL(file); 69 }else if(window.webkitURL){ 70 img.src = window.webkitURL.createObjectURL(file); 71 window.webkitURL.revokeObjectURL(file); 72 }else{ 73 (function(img){ 74 reader = new FileReader(); 75 reader.readAsDataURL(file); 76 reader.onload = function(){ 77 img.src= this.result; 78 }; 79 })(img); 80 }; 81 img.addEventListener('dragstart',function(e){e.preventDefault();e.stopPropagation();},false) 82 editRemark.addEventListener('blur',handleBlur,false); 83 }); 84 return fragment; 85 }; 86 function handleControl(e){ 87 var target = e.target,editRemarks = $('sbi_content').querySelectorAll('.editRemark'); 88 if(target.classList.contains('editRemark')) return; 89 each(editRemarks,function(){ 90 if(this.classList.contains('show')) this.classList.remove('show'); 91 }); 92 target.classList.contains('edit') && handleEdit(target); 93 target.classList.contains('del') && handleDel(target); 94 }; 95 function handleEdit(obj){ 96 var parent = closet(obj,'li'),related = parent.querySelectorAll('.editRemark')[0]; 97 parent.classList.add('show'); 98 related.classList.add('show'); 99 }; 100 function handleDel(obj){ 101 var parent = closet(obj,'li'),dels = closet(obj,'.imgList').querySelectorAll('.del'); 102 oFiles.splice(getIndex(dels,obj),1); 103 parent.parentNode.removeChild(parent); 104 }; 105 function handleBlur(){ 106 var parent = closet(this,'li'),remark = parent.querySelectorAll('.remark')[0],img = parent.querySelectorAll('.img_preview img')[0],v = this.value; 107 parent.classList.remove('show'); 108 this.classList.remove('show'); 109 remark.classList[v !== '' ? 'add' : 'remove']('hasContent'); 110 remark.innerHTML = v.length > 20 ? (v.substr(0,20)+'...') : v; 111 img.setAttribute('rel',v); 112 }; 113 function handleCancel(e){ 114 e.stopPropagation(); 115 handleClose(e); 116 }; 117 function handleClose(e){ 118 e.stopPropagation(); 119 db.removeChild($('sbi_overlayer')); 120 db.removeChild($('sbi_contentOuter')); 121 handleFiles.box = ''; 122 handleFiles.ul = ''; 123 oFiles = []; 124 }; 125 function handleUpload(set){ 126 return function(){ 127 var imgs = $('sbi_content').querySelectorAll('.img_preview img'); 128 var pros = $('sbi_content').querySelectorAll('.progress'); 129 var len = imgs.length,i=0; 130 each(imgs,function(i){ 131 var formdata = new FormData(); 132 formdata.append('file[]',oFiles[i]); 133 formdata.append('remark[]',imgs[i].getAttribute('rel')); 134 ajax({ 135 url:set.url, 136 data:formdata, 137 progress:function(percent){ 138 if(set.progress){ 139 set.progress(percent); 140 return; 141 }; 142 pros[i].parentNode.classList.add('show'); 143 pros[i].style.width = percent + '%'; 144 }, 145 success:function(xhr){ 146 if(i==len-1){ 147 set.callback && set.callback(); 148 return; 149 }; 150 set.success(xhr); 151 i++; 152 }, 153 errorfn:function(){ 154 if(set.errorfn){ 155 set.errofn(xhr); 156 return; 157 }; 158 i++; 159 } 160 }); 161 }); 162 }; 163 }; 164 function createWindow(set){ 165 var w = Math.max(db.scrollWidth,doc.documentElement.clientWidth),h=Math.max(db.scrollHeight,doc.documentElement.clientHeight); 166 var overlayer = createEl('<div id="sbi_overlayer" style="width:100%;height:100%;position:fixed;top:0;left:0;background:#000;opacity:.8"></div>',db); 167 var contentOuter = createEl('<div id="sbi_contentOuter" style="width:'+set.boxWidth+'px;height='+set.boxHeight+'px;position:fixed;top:50%;left:50%;margin:-'+set.boxHeight/2+'px 0 0 -'+set.boxWidth/2+'px"></div>',db); 168 var close = createEl('<a id="close" href="javascript:void(0)" style="float:right">CLOSE</a>',contentOuter); 169 var content = createEl('<div id="sbi_content" style="clear:both;max-height:'+set.boxHeight+'px;overflow-y:auto"></div>',contentOuter); 170 var btnBox = createEl('<div id="sbi_btnBox"></div>',contentOuter); 171 var btnUpload = createEl('<input id="sbi_upload" type="button" name="sbi_upload" value="上传" />',btnBox); 172 var btnCancel = createEl('<input id="sbi_cancel" type="button" name="sbi_cancel" value="取消" />',btnBox); 173 return { 174 overlayer:overlayer, 175 contentOuter:contentOuter, 176 close:close, 177 content:content, 178 btnBox:btnBox, 179 btnUpload:btnUpload, 180 btnCancel:btnCancel 181 }; 182 }; 183 function ajax(opts){return new ajax.prototype.init(opts);}; 184 ajax.prototype = { 185 constructor:ajax, 186 init:function(opts){ 187 var xhr = new XMLHttpRequest(); 188 var set = extend({ 189 url:'', 190 data:'', 191 progress:function(){}, 192 success:function(){}, 193 errorfn:function(){} 194 },opts||{}); 195 xhr.open('post',set.url,true); 196 xhr.onprogress = xhr.upload.onprogress = function(e){ 197 set.progress(e.loaded*100 / e.total); 198 }; 199 xhr.onload = function(){ 200 set.success(xhr); 201 }; 202 xhr.onerror = function(){ 203 set.errorfn(xhr); 204 }; 205 xhr.send(set.data); 206 } 207 }; 208 ajax.prototype.init.prototype = ajax.prototype; 209 210 /*****************************************************************************/ 211 function $(id){ 212 return typeof id == 'string' ? doc.getElementById(id) : id; 213 }; 214 function extend(target,source){ 215 for(var key in source) target[key] = source[key]; 216 return target; 217 }; 218 function createEl(str,parent){ 219 var div = doc.createElement('div'),el; 220 div.innerHTML = str; 221 el = div.firstChild; 222 parent && parent.appendChild(el); 223 return el; 224 }; 225 function each(arr,fn){ 226 var i=0,len=arr.length; 227 for(;i<len;i++){ 228 fn.call(arr[i],i,arr); 229 } 230 }; 231 function getIndex(arr,item){ 232 for(var i=0,len=arr.length;i<len;i++){ 233 if(arr[i] == item){ 234 return i; 235 }; 236 }; 237 return -1; 238 }; 239 function merge(target,source){ 240 for(var i=0,len=source.length;i<len;i++) target.push(source[i]); 241 return target; 242 }; 243 function closet(obj,match){ 244 var flag = true; 245 do{ 246 obj = obj.parentNode; 247 (/^\.[-\w]+$/.test(match) && obj.classList.contains(match)) && (flag = false); 248 (/^[-\w]+$/.test(match) && obj.nodeName.toLowerCase() == match ) && (flag = false); 249 }while(obj.nodeName && obj != db && flag); 250 return obj 251 }; 252 })(window);
CSS:
1 @charset "utf-8"; 2 /* CSS Document */ 3 @font-face {font-family: 'IcoMoon';src: url('IcoMoon.eot');src: url('IcoMoon.eot?#iefix') format('embedded-opentype'),url('IcoMoon.svg#IcoMoon') format('svg'),url('IcoMoon.woff') format('woff'),url('IcoMoon.ttf') format('truetype');font-weight: normal;font-style: normal;} 4 html,body {height:100%;} 5 body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { margin:0; padding:0; } 6 body, button, input, select, textarea { font: 12px/1.5 "微软雅黑", "宋体", Arial; } 7 button, input, select, textarea,img {vertical-align: middle;} 8 ul{ list-style:none;} 9 em { font-style: normal;} 10 a{ color:#fff; text-decoration: none;} 11 a:hover{color:#fff; text-decoration: none;} 12 13 .sbi_item{ display:inline-block; width:220px; height:138px; margin:10px 0 0 10px; position:relative;} 14 .sbi_item:hover .remark{opacity:.8;color:#666;-webkit-transition: all 0.3s ease-in-out;} 15 .sbi_item:hover .control{opacity:.8;-webkit-transition: all 0.3s ease-in-out;} 16 .remark {position: absolute;top:0;left:0;width: 100%;background: #000; opacity: 0;color:#333;z-index: 10;-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box; text-align:left;} 17 .hasContent {padding:8px;} 18 .control {position: absolute;bottom:0;left:0;width:100%; background: #000; opacity: 0;color:#fff;height:25px; line-height:25px; text-align:right;z-index: 10;} 19 .control a{padding-right:10px; color:#666;} 20 .control a .icon {color:#666;} 21 .control a:hover, .control a:hover .icon {color:#fff;} 22 .progressbox {width:100%;height:5px;position: absolute; bottom:-5px; background: #333;z-index: 10; display:none; opacity: .8;} 23 .progressbox.show{display:block;} 24 .progress { background: blue;display:block;height:5px;} 25 .editRemark {position: absolute;bottom:-55px;left:0;width:99%;height:50px; display:none;z-index: 10;} 26 .editRemark.show{ display:block;} 27 .img_preview {display:table-cell; vertical-align: middle;width:220px;height:138px;overflow:hidden;} 28 .img_preview img {/* position:relative;top:50%;left:50%;*/display:block; margin:0 auto; max-width:220px;max-height:138px;z-index:0;} 29 .icon { font-family: 'IcoMoon'; font-size:18px;display:inline-block;zoom:1;letter-spacing:0px;line-height:18px; margin-right:5px;text-align:center;vertical-align:-3px;color:#fff;} 30 .del:before {font-family: 'IcoMoon'; font-size:18px; content:'G';font-size:18px; line-height:18px;padding-right:5px;vertical-align:-3px;} 31 .edit:before{font-family: 'IcoMoon'; font-size:18px; content:'D';font-size:18px; line-height:18px;padding-right:5px;vertical-align:-3px;} 32 #close:before {font-family: 'IcoMoon'; font-size:18px; content:'4';font-size:18px; line-height:18px;padding-right:5px;vertical-align:-3px;} 33 #sbi_btnBox { text-align:center; padding-top:10px;} 34 input[type="button"] {background: #333; border-radius:5px; padding:3px 30px; display: inline-block; margin:10px 5px 0; clear:both; color:#fff;}
PHP就自己去写吧,接收的数据就是图片(name=file)以及图片的说明文字(name=remark),用firebug看下提交的数据就知道了。