项目中经常需要文件上传,每次都要重复造轮子,所以决定将文件上传做成组件,方便使用。效果如图:
自我感觉效果还是可以的,而且使用的代码也变得十分清晰,前端的HTML代码非常简洁,如下:
<html> <head> <Metahttp-equiv="Content-Type"content="text/html;charset=gb2312"> <linkhref="fileuploader.css"rel="stylesheet"/> <scriptsrc="fileuploader.js"></script> </head> <body> <divid="imageList"></div> </body> <script> varfileWidget=null; (function(){ varimageList=document.getElementById("imageList"); fileWidget=newFileWidgt(imageList); fileWidget.newPlaceholder({url:"http://127.0.0.1:8000/App/upload.PHP"}); })(); </script> </html>
前端代码只需新建一个FileWidgt类,然后调用newPlaceholder方法即可,所有复杂的操作都封装到FileWidgt类中。接下来主要分析FileWidgt类。
首先先看一下该组件的结构图:
根据结构图编写代码:
functionFileWidgt(ui){ this.ui=ui; this.data="";//记录选中且已经上传并返回的结果 this.files=[];//用于记录已选中的文件,防止重复上传 } FileWidgt.prototype.newPlaceholder=function(s){ varfileholder=document.createElement("input");//内部隐藏的输入框 fileholder.setAttribute("type","file"); fileholder.setAttribute("name","file"); varplaceholder=document.createElement("div");//显示图片的容器 placeholder.setAttribute("class","image-itemspace"); varcloseButton=document.createElement('div');//关闭按钮 closeButton.setAttribute("class","image-close"); closeButton.innerHTML='X'; placeholder.appendChild(fileholder); placeholder.appendChild(closeButton); this.ui.append(placeholder);//显示图片的容器加入最外层容器 varthat=this; closeButton.addEventListener('click',function(event){ event.stopPropagation(); event.cancelBubble=true; setTimeout(function(){ that.data=that.data.replace(placeholder.getAttribute("image-data"),"");//data中去除该关闭的图片结果 that.data=that.data.replace(",","); if(that.data.length>0&&that.data.charAt(0)==","){ that.data=that.data.substring(1); }elseif(that.data.length>0&&that.data.charAt(that.data.length-1)==","){ that.data=that.data.substring(0,that.data.length-1); } that.ui.removeChild(placeholder);//去除关闭的显示容器 },0); },false); placeholder.addEventListener("click",fileholder.onclick,false);//点击调用文件上传 fileholder.addEventListener("change",function(e){//选中文件后上传图片 if(that.files.join(",").indexOf(fileholder.value)==-1){ varformData=newFormData(); formData.append("file",fileholder.files[0]); varxhr=null; if(window.ActiveXObject){ xhr=newActiveXObject("Microsoft.XMLHTTP"); }else{ xhr=newXMLHttpRequest(); } xhr.open(s.method||'POST',s.url,true); xhr.onreadystatechange=function(){//Ajax文件上传返回 if(xhr.readyState==4&&xhr.status==200){ varfilename=JSON.parse(xhr.responseText).filename; placeholder.style.backgroundImage='url('+filename+')';//替换当前添加图片为上传文件的图片 if(placeholder.getAttribute("image-data")==undefined||placeholder.getAttribute("image-data")==""){ placeholder.classList.remove('space'); placeholder.removeEventListener("click",false); placeholder.removeChild(fileholder); that.newPlaceholder(s);//新建一个添加的图标 } //给data值添加当前上传的文件地址 if(that.data==""){ that.data=filename; placeholder.setAttribute("image-data",filename); }else{ that.data+=","+filename; placeholder.setAttribute("image-data",filename); } } } xhr.send(formData); } },false); } FileWidgt.prototype.getData=function(){ returnthis.data; }
样式代码:
.image-item{ width:65px; height:65px; background-image:url(img/iconfont-tianjia.png); background-size:100%100%; display:inline-block; position:relative; border-radius:5px; margin-right:10px; margin-bottom:10px; border:solid1px#e8e8e8; } .image-iteminput[type="file"]{ position:absolute; left:0px; top:0px; width:100%; height:100%; opacity:0; cursor:pointer; z-index:0; } .image-item.image-close{ position:absolute; display:inline-block; right:-6px; top:-6px; width:20px; height:20px; text-align:center; line-height:20px; border-radius:12px; background-color:#FF5053; color:#f3f3f3; border:solid1px#FF5053; font-size:9px; font-weight:200; z-index:1; } .image-item.space.image-close{ display:none; }
<?PHP header("Access-Control-Allow-Origin:*"); file_put_contents("log.log",$_FILES['file']['name']); move_uploaded_file($_FILES['file']['tmp_name'],'upload/'.$_FILES['file']['name']); echojson_encode(array("filename"=>'http://'.$_SERVER["REMOTE_ADDR"].':'.$_SERVER["SERVER_PORT"].'/App/upload/'.$_FILES['file']['name'])); ?>