最近公司要作一個html5上傳的jquery插件,要在下先實現功能,要求顯示上傳進度,文件信息,斷點續傳等等。我一看,艾瑪!Σ(゚д゚lll),沒作過啊。沒辦法,(# ゚Д゚),只能去查資料了。
做爲一名還未畢業的大學僧,本人表示亞歷山大。不過還好是作出來了,不敢說代碼寫得很好,你們將就着看吧。
感謝如下文章提供的思考方向:
http://www.script-tutorials.com/pure-html5-file-upload/
http://fex.baidu.com/blog/2014/04/html5-uploader/javascript
因爲傳的時候不當心,文件弄錯了,如今bug已修復,對不起啊你們
考慮到服務器緣由如今中止上傳演示頁面,抱歉請你們諒解
演示地址:暫停
資源地址:我是下載地址php
HTML:css
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"> <title>upload html5</title> <link rel="stylesheet" type="text/css" href="css/style.css"> <link rel="stylesheet" type="text/css" href="css/upload.css"> </head> <body ontouchmove="event.preventDefault()"> <div id="upload_box"> <form id="upload_form" name="upload_form" action="javascript:init();" method="post" enctype="multipart/form-data"> <div><label for="file">Please select file</label></div> <div><input type="file" id="file" name="file" onchange="fileReady()"><div> <input type="submit" id="submit" name="submit" value="上傳"> <button id="clear" onclick="clearUploadFile()">清除</button> <div class="upload_message_show"> <!--進度條--> <div class="upload_bar_box"> <div class="upload_bar"></div> <span class="upload_percent"></span> </div> <!--上傳剩餘時間和上傳速度--> <div class="upload_count"> <div class="left_time">剩餘時間 | 00:00:00</div> <div class="speed">100k/s</div> </div> <!--文件信息--> <div class="upload_file_message"> <div class="message_box"> <div class="upload_file_name"></div> <div class="upload_file_size"></div> <div class="upload_file_type"></div> <div class="upload_file_error"></div> <div class="isCompleted"></div> </div> <!--文件預覽--> <div class="upload_file_preview"></div> </div> </div> </div> <script type="text/javascript" src="js/html5_upload_ano.js"></script> </body> </html>
CSS:html
style.csshtml5
/*************reset****************/ html{color:#333;-webkit-text-size-adjust:none;height:100%;max-height:100%;overflow: hidden;font-family: 'Microsoft Yahei';} body{height: 100%;max-height:100%;overflow: hidden;} body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;} table{border-collapse:collapse;border-spacing:0;} fieldset,img{border:0;} address,caption,cite,code,dfn,em,var,optgroup{font-style:inherit;font-weight:inherit;} del,ins{text-decoration:none;} li{list-style:none;} h1,h2,h3,h4,h5,h6{font-size:100%;}q:before,q:after{content:'';} abbr,acronym{border:0;font-variant:normal;} sup{vertical-align:baseline;} sub{vertical-align:baseline;}legend{color:#000;} input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;} body{font-size:12px;} a{color: #333333;text-decoration: none;} a:hover{text-decoration:underline; color:#c00;} /*font*/ *{ font-size: 1.05em; color: #222; font-family: "Microsoft Yahei"; }
upload.cssjava
#upload_box{ padding:0em 1em; padding-top:20px; height:100%; background: #74b1d1; position: relative; } #upload_form{ background: #fff; height: 80%; padding: 1.4em 1em; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.7); } #upload_form label{ font-size: 1.5em; font-weight: bolder; } #file{ margin:20px 0; border:1px solid #ccc; border-radius: 5px; padding: 0.5em; font-size: 1.4em; width: 90%; } #submit,#clear{ font-size:1.2em; padding:0.3em 1.2em; border-radius:10px; border:1px solid #d9d9d9; background: -webkit-linear-gradient(#ffffff,#dfdfdf); background: -o-linear-gradient(#ffffff,#dfdfdf); background: -moz-linear-gradient(#ffffff,#dfdfdf); background: linear-gradient(#ffffff,#dfdfdf); box-shadow:0px 1px 3px rgba(0,0,0,0.7); outline: none; } #submit{ margin-right:1.6em; } #submit:hover,#clear:hover{ background: -webkit-linear-gradient(#66ccff,#74b1d1); background: -o-linear-gradient(#66ccff,#74b1d1); background: -moz-linear-gradient(#66ccff,#74b1d1); background: linear-gradient(#66ccff,#74b1d1); cursor: pointer; } .upload_message_show{ margin-top: 20px; display: none; } .upload_file_message{ padding: 1.4em 0em; padding-left: 60%; padding-right: 1.2em; border-radius: 10px; background: -webkit-linear-gradient(#dfdfdf,#cccccc); background: -o-linear-gradient(#dfdfdf,#cccccc); background: -moz-linear-gradient(#dfdfdf,#cccccc); background: linear-gradient(#dfdfdf,#cccccc); font-size: 1.1em; font-weight: bolder; position: relative; min-height: 6.5em; } .upload_file_error{ color:red; } .message_box{ position: absolute; left: 1.2em; top: 1.4em; } .upload_file_preview{ height: 100%; position: relative; } .upload_bar_box{ width: 100%; height: 1em; border-radius:0.5em; position: relative; box-shadow:0px 0px 3px rgba(0,0,0,0.6); line-height: 1em; } .upload_bar{ width:0%; border-radius:0.5em; background:-webkit-linear-gradient(#F01731,#F50B43); background:-o-linear-gradient(#F01731,#F50B43); background:-moz-linear-gradient(#F01731,#F50B43); background:linear-gradient(#F01731,#F50B43); height:100%; } .upload_percent{ position: absolute; right: 10px; top:0em; font-weight:700; } .upload_count{ width: 100%; font-size:0.8em; margin-top:1em; position: relative; } .left_time{ margin-left: 1em; } .speed{ position: absolute; right:1em; top: 0em; }
js:jquery
變量定義:linux
var nSlice_count = 100,//分段數,文件分段數 nFactCount, //實際分段數 nMin_size = 0.5,//最小分段大小(M) nMax_size = 5, //最大分段大小(M) nFactSize, //實際分段大小 nCountNum = 0, //分段標號 sFile_type, //文件類型 nFile_load_size, //文件上傳部分大小 nFile_size, //文件大小 nPreuploaded = 0, //上一次記錄上傳部分的大小 bIs_uploading= false,//是否上傳中 bStart_upload= false,//是否開始上傳 bEnd_upload = false;//是否上傳完成
當文件域變化或者點擊清空時,重置全部已記錄信息:android
function messageChange(){ document.querySelector(".upload_file_name").innerHTML ="文件名稱: " ; document.querySelector(".upload_file_type").innerHTML ="文件類型: " ; document.querySelector(".upload_file_size").innerHTML ="文件大小: " ; document.querySelector(".isCompleted").innerHTML ="上傳狀態: " ; document.querySelector(".upload_bar").style.width = "0%"; document.querySelector(".upload_percent").innerHTML = "0%"; document.querySelector(".upload_file_preview").innerHTML =""; document.querySelector(".upload_message_show").style.display = "none"; } function clearUploadFile(e){ var e = e || event; e.stopPropagation(); e.preventDefault(); document.getElementById("file").value = ""; bStart_upload = false; messageChange(); } function fileReady(){ bIs_uploading = false; bEnd_upload = false; nCountNum = 0; bStart_upload = false; messageChange(); }
發生錯誤時的處理:web
function errorUp(){ bStart_upload = false; document.querySelector(".upload_file_error").innerHTML = "上傳過程當中出錯"; } function abortUp(){ bStart_upload = false; document.querySelector(".upload_file_error").innerHTML = "網絡故障,請檢查重試"; }
文件上傳後提供預覽,考慮到手機小屏幕的問題,只在ipad和pc上提供預覽,預覽的文件類型爲
image/video/audio,因爲瀏覽器對多媒體格式的支持不一樣,不能保證每一個文件都能正常播放
function filePreview($src){ var ftype = sFile_type; var $temp; var IMGMaxHeight = document.querySelector(".upload_message_show").offsetHeight; switch(ftype){ case "image" : $temp = '<img src="source/'+$src.url+'" style="max-height:'+IMGMaxHeight+'px;margin-left:30%;">'; break; case "audio" : $temp = '<audio src="source/'+$src.url+'" controls="controls"></audio>'; break; case "video" : $temp = '<video src="source/'+$src.url+'" controls="controls"></video>'; break; } var IsPreview = checkUserAgent(); if(IsPreview) document.querySelector(".upload_file_preview").innerHTML = $temp; } function checkUserAgent(){ var msg = true; var agent = ["ipod","iphone","android","symbian","windows mobile"]; var info =navigator.userAgent.toLowerCase(); for(var i=0,j=agent.length;i<j;i++) { if(info.indexOf(agent[i])>0) msg = false; } return msg; }
數據單位轉化:
var conversion = (function(){ var unitConversion = { bytesTosize:function(data){ var unit = ["Bytes","KB","MB","GB"]; var i = parseInt(Math.log(data)/Math.log(1024)); return (data/Math.pow(1024,i)).toFixed(1) + " " + unit[i]; }, secondsTotime:function(sec){ var h = Math.floor(sec/3600), m = Math.floor((sec-h*3600)/60), s = Math.floor(sec-h*3600-m*60); if(h<10) h = "0" + h; if(m<10) m = "0" + m; if(s<10) s = "0" + s; return h + ":" + m + ":" + s + ":"; } }; return unitConversion; })();
文件上傳和上傳時的計算:
//start sending var reader = new FileReader(); var timer; var fProgress = function(e){ var fSize = get_file_message.getAll().fileSize; timer = setTimeout(uploadCount(e,fSize,conversion),300); }; var floadend = function(e){ if(reader.error){alert("上傳失敗,出現未知錯誤");clearTimeout(timer);return;} clearTimeout(timer); if(nCountNum+1!=nFactCount) { if(bStart_upload) { nCountNum++; uploadStart(); return; } else { document.querySelector(".speed").innerHTML = "0k/s"; document.querySelector(".left_time").innerHTML = "剩餘時間 | 00:00:00"; return; } } bEnd_upload = true; document.querySelector(".layer_box").style.display = "none"; document.querySelector(".speed").innerHTML = "0k/s"; document.querySelector(".left_time").innerHTML = "剩餘時間 | 00:00:00"; document.querySelector(".upload_percent").innerHTML = "100.00%"; document.getElementById("submit").value = "上傳"; var $res = JSON.parse(e.target.responseText); filePreview($res); if($res.res=="success") bIs_uploading =true; document.querySelector(".isCompleted").innerHTML="上傳狀態: " + (bIs_uploading?"上傳完成":"正在上傳.."); }; var uploadStart = function(){ var get_all = get_file_message.getAll(); var start = nCountNum * nFactSize, end = Math.min(start+nFactSize,get_all.fileSize); var fData = new FormData(); fData.append("file",file.slice(start,end)); fData.append("name",file.name); fData.append("size",file.size); fData.append("type",file.type); fData.append("totalCount",nFactCount); fData.append("indexCount",nCountNum); fData.append("trueName",file.name.substring(0,file.name.lastIndexOf("."))); document.querySelector(".layer_box").style.display = "block"; if(!sFile_type) sFile_type = file.type.substring(0,file.type.indexOf("/")); var xhr = new XMLHttpRequest(); xhr.upload.addEventListener("progress",fProgress,false); xhr.addEventListener("load",floadend,false); xhr.addEventListener("error",errorUp,false); xhr.addEventListener("abort",abortUp,false); xhr.open("POST","php/send/"); xhr.send(fData); }; reader.onloadstart = function(){ var get_all = get_file_message.getAll(), fName = get_all.fileName, fType = get_all.fileType, fSize = conversion.bytesTosize(get_all.fileSize); document.querySelector(".upload_message_show").style.display = "block"; document.querySelector(".upload_file_name").innerHTML ="文件名稱: " + fName; document.querySelector(".upload_file_type").innerHTML ="文件類型: " + fType; document.querySelector(".upload_file_size").innerHTML ="文件大小: " + fSize; document.querySelector(".isCompleted").innerHTML ="上傳狀態: " + (bIs_uploading?"完成":"正在上傳中.."); nFactSize = get_all.fileSize/nSlice_count; nFactSize = (nFactSize>=nMin_size*1024*1024?nFactSize:nMin_size*1024*1024); nFactSize = (nFactSize<=nMax_size*1024*1024?nFactSize:nMax_size*1024*1024); nFactCount= Math.ceil(get_all.fileSize/nFactSize); uploadStart(); }; reader.readAsBinaryString(file); } function uploadCount(e,fSize,conversion){ var upSize = e.loaded+nCountNum*nFactSize, perc = (upSize*100/fSize).toFixed(2) + "%"; var speed = Math.abs(upSize - nPreuploaded); if(speed==0){clearTimeout("timer");return;} var leftTime = conversion.secondsTotime(Math.round((fSize-upSize)/speed)); speed = conversion.bytesTosize(speed)+"/s"; document.querySelector(".speed").innerHTML = speed; document.querySelector(".left_time").innerHTML = "剩餘時間 | " + leftTime; document.querySelector(".upload_percent").innerHTML = perc; document.querySelector(".upload_bar").style.width = perc; nPreuploaded = upSize; }
PHP:
<?php $fsize = $_POST['size']; $findex =$_POST['indexCount']; $ftotal =$_POST['totalCount']; $ftype = $_POST['type']; $fdata = $_FILES['file']; $fname = mb_convert_encoding($_POST['name'],"gbk","utf-8"); $truename = mb_convert_encoding($_POST['trueName'],"gbk","utf-8"); $path = "../../"; $dir = $path."source/".$truename."-".$fsize; $save = $dir."/".$fname; if(!is_dir($dir)) { mkdir($dir); chmod($dir,0777); } //讀取臨時文件內容 $temp = fopen($fdata["tmp_name"],"r+"); $filedata = fread($temp,filesize($fdata["tmp_name"])); //將分段內容存放到新建的臨時文件裏面 if(file_exists($dir."/".$findex.".tmp")) unlink($dir."/".$findex.".tmp"); $tempFile = fopen($dir."/".$findex.".tmp","w+"); fwrite($tempFile,$filedata); fclose($tempFile); fclose($temp); if($findex+1==$ftotal) { if(file_exists($save)) @unlink($save); //循環讀取臨時文件並將其合併置入新文件裏面 for($i=0;$i<$ftotal;$i++) { $readData = fopen($dir."/".$i.".tmp","r+"); $writeData = fread($readData,filesize($dir."/".$i.".tmp")); $newFile = fopen($save,"a+"); fwrite($newFile,$writeData); fclose($newFile); fclose($readData); $resu = @unlink($dir."/".$i.".tmp"); } $res = array("res"=>"success","url"=>mb_convert_encoding($truename."-".$fsize."/".$fname,'utf-8','gbk')); echo json_encode($res); } ?>
還有一些細節的js這裏沒給出來,主要就上面的功能,有問題的話歡迎回復,樓主只是個新手,不足之處請你們多多見諒。